2

我最近在 WebFaction 上遇到了我的 Django 项目和内存使用问题。

这是 webfaction 上这个项目在内存中运行的两个进程:

30396  4-20:20:00 13486 
30404  4-20:20:00 13487 

视图运行后,其中一个进程将大幅增加:

69720  4-20:20:22 13486 
30404  4-20:20:22 13487 

如您所见,第一个进程的内存使用量增加了一倍多!由于经常使用此功能,我需要弄清楚发生了什么。我相信我已经将其缩小到以下视图(上传图像、添加细节、裁剪缩略图的 3 步过程)。

这是下面的视图。它获取一个照片对象,从文件中加载图像,获取用户提交的框坐标,然后创建一个 200,200 大小的图像。这个新创建的图像被写回磁盘,文件名中带有 .thumbnail,并且照片对象被保存。

@login_required
def upload3(request, photo_pk):
    photo = get_object_or_404(Photo, pk=photo_pk, user=request.user)
    if request.method == "POST":
        form = upload3Form(request.POST)
        if form.is_valid():
            im = Image.open(photo.image.path)
            try:
                box =(form.cleaned_data['x1'],form.cleaned_data['y1'],form.cleaned_data['x2'],form.cleaned_data['y2'])
            except:
                box = ('0','0','1000','1000')
            cropped = im.crop(box)
            cropped.thumbnail((200,200),Image.ANTIALIAS)
            result = os.path.splitext(photo.image.path)
            cropped.save(result[0] + '.thumbnail' + result[1])
            photo.status = 3
            photo.save()

任何关于我可能做错的想法将不胜感激。

Update 1:用于测试的图像均为 Jpeg,尺寸约为 3600 x 2700,每张图像约为 2 MB。

4

2 回答 2

2

2M 数字是针对压缩的 JPEG 图像,但未压缩的 3600 x 2700 真彩色将约为 38M(9,720,000 像素,每像素 4B),接近您正在经历的内存使用增加。

这是 PIL 的一个已知问题,我可以通过将 40000x40000 像素的黑色图片作为 png 发送给您来生成像素炸弹。在加载之前始终检查分辨率(或使用 try/except 块处理 OutOfMemory 保护代码)。查看使用 im.tile 属性逐块处理图像是否会降低内存占用。

可能值得检查:

据说在处理较大图像时可以更好地处理内存的一些替代方案:

[ 更新 ]

你知道 PIL 中是否有办法从内存中释放对象?因为从理论上讲,这对这个视图来说是最好的,因为我需要它像它一样工作,但只是更好地处理图像。

  • 为了避免内存峰值,您可以检测巨大的图像并尝试使用im.tile而不是im.crop(不幸的是在较低级别运行)以块的形式处理它们。
  • 您可以尽快删除中间图像对象以获得更短的尖峰(使用gc 模块,您可以强制垃圾收集器进行清理)。
于 2012-03-06T08:42:02.273 回答
0

经过大量的挖掘和死胡同,我尝试了一些在任何地方都没有建议的东西,它奏效了。

在每个包含 PIL 中使用的图像对象的对象上,一旦完成,我就必须删除该对象。例如:

im = Image.open(photo.image.path)
try:
    box  =(form.cleaned_data['x1'],form.cleaned_data['y1'],form.cleaned_data['x2'],form.cleaned_data['y2'])
except:
    box = ('0','0','1000','1000')
cropped = im.crop(box)
newimage = cropped.resize((form.cleaned_data['dw'],form.cleaned_data['dh']),Image.ANTIALIAS)
del im
del cropped 

因此,一旦我完成了该对象,我就在该项目上调用 del。它似乎已经解决了这个问题。我不再有记忆增加,我不能更快乐。

于 2012-03-15T15:25:29.437 回答