Django:上传的文件没有被垃圾收集,导致内存问题

Posted

技术标签:

【中文标题】Django:上传的文件没有被垃圾收集,导致内存问题【英文标题】:Django: Uploaded files not being garbage collected, causing memory problems 【发布时间】:2012-08-07 01:31:37 【问题描述】:

我有一个处理上传文件的 Django 视图,当它被重复调用时,我们总是遇到内存溢出错误。 (我们在 Heroku 上,所以每个 web dyno 有 512mb 的内存)。

内存溢出错误表明每次调用都会根据文件大小增加内存使用量,并且内存使用量永远不会下降。我认为服务器将图像读入内存以将其保存到 Django 模型中,但完成后永远不会释放内存。

我认为函数返回后必须存在对图像的引用,以防止图像被垃圾收集。但我想不出那会是什么。

这是代码的简化版本,我对其进行了测试以确保它存在相同的问题:

def simplified_add_image(request, biz_id):
    if request.is_ajax():
        # the file is stored raw in the request
        newBI = NewBusinessImage(business_id=biz_id, name=request.GET.get("name"), primary_image=True)
        newBI.id = uuid.uuid4()
        newBI.save()
        uniquename = biz_id + ".." + get_a_uuid() + ".jpg"

        newBI.original_image.save(uniquename, ContentFile(request.read()))

        # this starts a series of tasks to process the image into various sizes.
        # don't think it's the problem because it runs on a separate server, and the
        # web server is the one that goes over memory
        tasks.image_meta_task.delay(uniquename, newBI.id)

        return StockJSONResponse(request, 
            "success" : True,
        )

非常感谢任何帮助。非常感谢!

粘土

以下是 cmets 中要求的附加信息:

我们将文件存储在 AmazonS3 上:

DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
STATICFILES_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
STATIC_URL = 'https://s3.amazonaws.com/%s/' % AWS_STORAGE_BUCKET_NAME
from S3 import CallingFormat
AWS_CALLING_FORMAT = CallingFormat.SUBDOMAIN

这里是 NewBusinessImage 模型

class NewBusinessImage(models.Model):
    id = UUIDField(auto=True,primary_key=True,version=4, default=uuid.uuid4())
    business = models.ForeignKey('Business')
    name = models.CharField(max_length=100)
    original_image = models.ImageField(upload_to='photos/originals/')
    thumbnail = models.ImageField(upload_to='photos/thumbnails/')
    display_image = models.ImageField(upload_to='photos/displays/')
    enlarged_image = models.ImageField(upload_to='photos/enlarged/')
    num_views = models.PositiveIntegerField(editable=False, default=0)
    primary_image = models.BooleanField(default=False)

【问题讨论】:

这是什么image_meta_task.delay 这是一个异步 Celery 任务,它在单独的服务器(不是我的网络服务器)上启动,将图像处理成标准尺寸并保存。 如果这是一个简化版,那说明你去掉image_meta_task.delay就没有内存问题?另外,您将文件存储在哪里?你能发布settings.py storege设置和NewBusinessImage吗? @danihp 添加了您要求的信息。老实说,我没有在没有 image_meta_task.delay 的情况下测试这个函数,因为这个任务是保持我们的数据库健全所必需的。我想是因为它在不同的服务器上执行,所以即使是简化版本也可以安全地留在其中。您认为这可能涉及/部分问题吗? 您是否尝试在 newBI.save() 之后将 newBI 设置为 None ?抱歉,这只会释放一半的内存,因为请求也有图像字节...... 【参考方案1】:

根据 Django 文档,它附带 2 个文件上传处理程序。内存和临时文件处理程序 (Link to docs)

如果您将设置 FILE_UPLOAD_HANDLERS 设置为仅包含“django.core.files.uploadhandler.TemporaryFileUploadHandler”,则它永远不应将文件保存到内存中,并且从技术上讲永远不会导致您目前面临的内存问题。

另一种选择是将FILE_UPLOAD_MAX_MEMORY_SIZE 设置为少量,这将导致上传直接进入磁盘。

【讨论】:

以上是关于Django:上传的文件没有被垃圾收集,导致内存问题的主要内容,如果未能解决你的问题,请参考以下文章

内存泄漏与溢出

Java垃圾收集学习笔记

9.1为什么要使用垃圾收集

JVM 垃圾收集器与内存分配策略

垃圾收集器与内存分配策略---垃圾收集算法

垃圾收集器与内存分配策略之垃圾收集算法