Django Python 垃圾回收烦恼

13 投票
5 回答
6337 浏览
提问于 2025-04-16 09:23

经过两天的调试,我终于找到了让我程序变慢的罪魁祸首:Python的垃圾回收器。
我的应用程序在内存中保存了很多对象,而且运行得很好。
垃圾回收器会定期进行检查(我没有调整默认的阈值(700, 10, 10))。
但有时候,在一个重要的交易过程中,第二代的回收会启动,检查我大约150万个第二代对象。
这要花费2秒钟! 而正常的交易只需要不到0.1秒。

我想知道我该怎么办?
我可以通过设置一个非常高的阈值来关闭第二代的回收(这样做对吗?),这样垃圾回收器就会听话。
我应该什么时候再开启它们呢?
我们使用Django实现了一个网络服务,每个用户请求大约需要0.1秒。
理想情况下,我希望在用户API请求之间运行这些第二代的垃圾回收。但我该怎么做呢?
我的视图以return HttpResponse()结束,之后我想运行一次第二代的垃圾回收。
我该怎么做?这样做有意义吗?

我能否标记那些永远不需要被垃圾回收的对象,这样垃圾回收器就不会在每个第二代周期检查它们?
我该如何配置垃圾回收器,让它在Django服务器相对空闲时进行全面的回收?

使用的是Python 2.6.6,运行在多个平台上(Windows / Linux)。

5 个回答

1

另一种选择是完全关闭垃圾回收(GC),然后设置mod_wsgi(或者你正在使用的其他工具)让它更频繁地结束和重启进程。

4

我认为一个选择是完全关闭垃圾回收,然后在请求结束时手动进行垃圾回收,具体可以参考这里的内容:垃圾回收机制是如何工作的?

我想你可以在你的 settings.py 文件中关闭垃圾回收。

如果你想在每次请求时都进行垃圾回收,我建议你开发一些中间件,在处理响应的方法中进行:

import gc
class GCMiddleware(object):
    def process_response(self, request, response):
        gc.collect()
        return response
8

我们在使用gunicorn的时候做过类似的事情。根据你使用的wsgi服务器,你需要找到在响应之后的合适钩子,而不是在之前。Django有一个叫request_finished的信号,但这个信号还是在响应之前触发的。

对于gunicorn,在配置中你需要定义两个方法,像这样:

def pre_request(worker, req):
    # disable gc until end of request
    gc.disable()


def post_request(worker, req, environ, resp):
    # enable gc after a request
    gc.enable()

这里的post_request是在http响应发送之后运行的,所以这是进行垃圾回收的一个非常好的时机。

撰写回答