2

在 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 仍然在触发错误之前提供最后一个请求,但我确信这是一件不受欢迎的事情,我想避免它......)

谢谢!!!

4

0 回答 0