2012-02-28 59 views
2

我最近遇到了一个问题,我的Django项目和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。

+0

您是否缩小了视图中的哪些操作会导致内存使用增加?如果视图被多次调用会发生什么? – 2012-02-28 00:02:31

+0

不,我没有,因为我无法在活动服务器(如pdb)上执行尽可能多的调试。似乎并不是每次调用视图时都会发生,但大多数情况下都是如此。 (几个星期前我上传了几张图片后,一次处理的内存使用量高于112 MB)。 – Fernker 2012-02-28 00:11:05

+0

你介意用典型的图像大小和格式更新你的问题吗? – 2012-03-05 22:32:52

回答

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该项。它似乎已经解决了这个问题。我不再有记忆力增加,我不能更快乐。

+0

用你找到的解决方案更新你的问题,而不是回答你自己的问题,并从我的答案中取回接受,会更好。 – 2012-03-15 17:07:17

+0

我觉得我的答案更完整,当人们提出问题时,他们比绿色复选框更适合原始问题的更新。我仍然给你赏金... – Fernker 2012-03-21 17:10:53

2

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

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

可能需要检查:

一些替代品与较大的图片的时候可以更好地处理内存说:

  • GDAL(地理空间数据抽象库)
  • OIIO(OpenImageIO)
  • Mahotas(NumPy的)

[更新]

你知道,如果有一个在PIL的方式从内存中释放对象做什么?因为理论上这对于这个观点来说是最好的,因为我需要它像它一样工作,但是更好地处理图像。

  • 为了避免内存尖峰可以检测巨大的图像,并尝试处理他们使用im.tile块代替im.crop(可惜的是在较低的水平运行)。
  • 您可以尽快删除中间图像对象,以便获得更短的尖峰(使用gc module,您可以强制清理垃圾收集器)。
+0

哦,这是有道理的,我从来没有想过图片被压缩。我已经开始更多地了解你的建议,并且我会看看它们是否有效。你知道PIL中有没有办法从内存中释放对象?因为理论上这对于这个观点来说是最好的,因为我需要它像它一样工作,但是更好地处理图像。谢谢。 – Fernker 2012-03-06 15:24:00

+0

对不起,我没有意识到你已经更新了你的答案。谢谢你的回答,因为你提供了洞察导致内存峰值的原因。 (这是我的问题是)。我将与WebFaction交谈,看看他们是否有任何想法,因为我有一个体面的解决方案,不需要我花费几个小时的工作。 – Fernker 2012-03-08 16:30:38