You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Python内存分析器时刷新页面后函数内存占用持续增长原因排查

解决Python Web函数内存持续增长的问题

嘿,我来帮你捋捋这个内存持续增长的问题——我之前在Web应用里也碰到过类似的情况,用memory_profiler排查的时候头都大了,不过后来找到了几个常见的坑,给你参考下:

先排除工具本身的干扰

有时候@profile装饰器(尤其是memory_profiler库的实现)可能会保留一些统计数据,或者修改了函数的执行上下文,导致看起来内存一直在涨,但实际是工具本身的开销。你可以先去掉@profile,用Python自带的tracemalloc做个简单验证:

import tracemalloc

@login_required
def your_view(request):
    tracemalloc.start()
    snap_before = tracemalloc.take_snapshot()
    
    # 这里放你的函数逻辑
    
    snap_after = tracemalloc.take_snapshot()
    top_diff = snap_after.compare_to(snap_before, 'lineno')
    print("内存增长TOP5:")
    for stat in top_diff[:5]:
        print(stat)
    tracemalloc.stop()

如果去掉@profile后内存还是持续涨,那问题就出在你的代码逻辑里了。

最常见的几个内存泄漏原因

1. 全局/模块级变量在不断累积

这是最容易踩的坑!比如你在函数里往全局列表、字典或者模块级的缓存容器里添加元素,这些对象的引用会一直存在,gc根本无法回收它们。举个例子:

# 模块级的全局变量,每次调用函数都往里加东西
request_cache = []

@login_required
@profile
def your_view(request):
    data = fetch_some_data(request)
    request_cache.append(data)  # 这里每次调用都加,内存肯定涨!
    return render(request, 'page.html', {'data': data})

检查下你的函数里有没有修改全局变量、类的静态属性,或者自定义的缓存容器,有没有忘记清理这些内容。

2. 未正确关闭的资源/对象引用泄漏

比如打开的文件、数据库连接、网络会话对象,或者ORM查询出来的模型实例,被意外存到了长期存在的容器里,导致无法被回收:

  • 用open()的时候一定要用with语句自动关闭,不要手动打开后忘记close;
  • 数据库连接要放回连接池,或者用完就关闭;
  • 第三方库的对象(比如requests的Session)要正确关闭,避免持有连接或缓存数据。

另外,如果你的代码里有回调函数、事件监听器,记得在函数结束时移除它们,不然这些回调会持有对象引用,导致gc无法回收。

3. 循环引用+自定义__del__方法

Python的gc虽然能处理普通的循环引用,但如果循环引用中的对象自定义了__del__方法,gc会不知道先调用哪个对象的析构函数,直接把这些对象放到不可回收的列表里,导致内存泄漏。检查下你用到的类有没有自定义__del__,如果有的话,尽量改成其他方式清理资源。

进一步排查的工具

如果上面的方法还没找到问题,可以试试这两个工具:

  • objgraph: 用来查看对象的引用链,找到谁在持有那些无法被回收的对象。比如你发现list对象一直在涨,可以用objgraph.show_backrefs()查看引用它的对象:
    import objgraph
    
    @login_required
    def your_view(request):
        # 函数逻辑
        objgraph.show_most_common_types()  # 看当前内存里最多的对象类型
        # 如果找到了可疑对象,查看它的引用链
        # suspect_obj = get_suspect_object()
        # objgraph.show_backrefs([suspect_obj], filename='backrefs.png')
    
  • 手动触发gc并查看回收情况: 在函数末尾手动调用gc.collect(),并打印回收的对象数,看看gc到底有没有在干活:
    import gc
    
    @login_required
    @profile
    def your_view(request):
        # 函数逻辑
        collected_count = gc.collect()
        print(f"本次调用回收了 {collected_count} 个对象")
    

如果每次调用都能回收一些对象,但内存还是涨,说明有对象的引用一直没被释放,得继续找根源。

内容的提问来源于stack exchange,提问作者Abi Waqas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:44:29