Python服务器应用程序泄漏内存

我试图诊断为什么我的Python服务器应用程序泄漏内存。 该应用程序需要一个图像的请求使用Vipsresize,并返回图像。 在每次请求之后,内存使用量会随着原始图像的大小而大致增长。

from fapws import base import fapws._evwsgi as evwsgi from gi.repository import Vips import urllib2 import hmac import hashlib import base64 import StringIO from boto.s3.connection import S3Connection from boto.s3.bucket import Bucket def start(): evwsgi.start('0.0.0.0', '80') evwsgi.set_base_module(base) def lfrThumbnail(environ, start_response): try: parameters = environ['PATH_INFO'].split('/') s3File = 'my s3 url' + parameters[0] width = float(parameters[1]) height = float(parameters[2]) hmacSignatureUser = parameters[3] hmacSignature = some hasing code... if not (hmacSignatureUser == hmacSignature): print hmacSignatureUser print hmacSignature print hmacSignatureUser == hmacSignature raise Exception bufferedImage = urllib2.urlopen(s3File).read() image = Vips.Image.new_from_buffer(bufferedImage, '') imageWidth = float(image.width) imageHeight = float(image.height) imageAspectRatio = imageWidth / imageHeight if (width > imageWidth) or (height > imageHeight): image = image elif abs((imageAspectRatio / (width/height)) - 1) < 0.05: image = image.resize(width / imageWidth) else: scaleRatioWidth = width / imageWidth scaleRatioHeight = height / imageHeight maxScale = max(scaleRatioWidth, scaleRatioHeight) image = image.resize(maxScale) cropStartX = (image.width - width) / 2 cropStartY = (image.height - height) / 2 image = image.crop(cropStartX, cropStartY, width, height) except Exception, e: start_response('500 INTERNAL SERVER ERROR', [('Content-Type','text')]) return ['Error generating thumbnail'] start_response('200 OK', [ ('Content-Type','image/jpeg'), ('Cache-Control: max-stale', '31536000') ]) return [image.write_to_buffer('.jpg[Q=90]')] evwsgi.wsgi_cb(('/lfr/', lfrThumbnail)) evwsgi.set_debug(0) evwsgi.run() if __name__ == '__main__': start() 

我试过使用muppy,pympler跟踪器,但是在图像打开/closures操作之后,每个diff只显示了几个字节。

外部C库可能是内存泄漏的原因吗? 如果是这样,那么怎么debugging呢。

如果它是任何相关的我在docker集装箱内运行的python服务器

我是libvips维护者。 这听起来像vips操作caching:vips保留内存中的最后几个操作,并重新使用结果,如果可以的话。 在某些情况下,这可能是一个巨大的performance。

对于一个Web服务,你可能在其他地方caching,所以你不会想要这个,或者你至less不会想要一个大的caching。 您可以使用vips_cache_set_max()和朋友来控制caching大小:

http://www.vips.ecs.soton.ac.uk/supported/current/doc/html/libvips/VipsOperation.html#vips-cache-set-max

从Python是:

 Vips.cache_set_max(0) 

完全closurescaching。 您可以将caching设置为通过内存使用,文件描述符使用或操作次数进行限制。

有几个其他有用的东西可以设置来观察资源使用情况。 Vips.leak_set(True)使vips在退出时报告泄漏对象,并报告峰值像素缓冲区内存的使用情况。 Vips.cache_set_trace(True)使其跟踪调用的所有操作,并显示caching命中。

在你的代码中,我也会启用顺序模式。 将access = Vips.Access.SEQUENTIAL添加到您的new_from_buffer()

默认行为是打开图像进行完全随机访问(因为vips不知道最终在图像上运行的操作)。 对于像JPG这样的东西,这意味着vips会将图像解码为打开时的大型未压缩数组。 如果图像小于100MB,则会将该数组保存在内存中。

但是,对于简单的resize,您只需要从顶部到底部访问像素,以便在打开时提示顺序访问。 在这种模式下,vips将只能从input中一次解压缩几条扫描线,并不会保留整个未压缩的图像。 你应该看到内存使用和延迟下降。

还有很多其他的东西可以处理,比如exif autorotate,颜色pipe理,透明度,jpeg缩小加载等等,我相信你知道。 vipsthumbnail的来源可能是一个有用的参考:

https://github.com/jcupitt/libvips/blob/master/tools/vipsthumbnail.c