在 Google AppEngine 中使用 Python 2.7,为了向客户端提供修补的二进制文件,我这样做:
- 使用 BlobReader 从 blobstore 读取原始文件
- 将 BlobReader 中的数据输出到补丁点
- 输出修补的字节
- 输出原始数据的剩余部分
系统工作,但似乎在某处存在内存泄漏,因为在每次请求后,当前实例使用的内存会增加两倍的 blob 大小:例如,如果 blob 为 8 MB,则在请求后使用的内存由实例增加 16 MB。结果,仅在几次这样的请求之后,实例就被 GAE 强行终止,并显示“超出软私有内存限制”的错误消息。
这是产生内存泄漏的代码的缩短版本:
class CurrentVer(db.Expando):
"singleton entity with reference to the blob and starting position of the patch"
patch_start = db.IntegerProperty()
blob = blobstore.BlobReferenceProperty()
def out_blob(handler):
# prepare a patch string
patch_string = "<CONFIG><A>A316</A></CONFIG>"
# read blob key and starting position of patch
CurrVer = CurrentVer.get_by_key_name("CurrentVer")
patch_start = CurrVer.patch_start
blob_key = str(CurrVer.blob.key())
CurrVer = None
# open BlobReader object with 1MB buffer, as shown in GAE docs:
blob_reader = blobstore.BlobReader(blob_key, buffer_size=1048576)
# read original data until patch point, and output it:
handler.response.out.write(blob_reader.read(patch_start))
# output patch bytes
handler.response.out.write(patch_string)
# skip the bytes that have been patched
blob_reader.seek(patch_start + len(patch_string))
# read remaining original data until the end, and output it
handler.response.out.write(blob_reader.read())
blob_reader.close()
blob_reader = None
gc.collect()
def gc_collect(webapp2.RequestHandler):
def get(self):
gc.collect()
self.response.out.write("<html><body>Called cg.collect()</body></html>")
class patch_blob(webapp2.RequestHandler):
def get(self):
out_blob(self)
app = webapp2.WSGIApplication([('/patch_blob.*', patch_blob),
('/gc_collect.*', gc_collect)],
debug=True)
当代码运行时(URL = /patch_blob),每次请求后,实例使用的内存都会增加两倍的 blob 大小,如下所示:
请求 1:55 MB
请求 2:73 MB
请求 3:90 MB
...依此类推,直到我在日志中收到此错误:
(c) 在服务 5 个请求后,超过了 140.504 MB 的软私有内存限制
(w) 处理完这个请求后,发现处理这个请求的进程占用了太多内存,被终止了。这可能会导致一个新进程被用于对您的应用程序的下一个请求。如果您经常看到此消息,则您的应用程序中可能存在内存泄漏。
谁能解释发生了什么,以及如何避免看起来像严重的内存泄漏?(幸运的是,GAE 仍然在触发错误之前提供最后一个请求,但我确信这是一件不受欢迎的事情,我想避免它......)
谢谢!!!