Python内存泄漏

Fra*_*rth 164 python debugging memory-leaks memory-management

我有一个长时间运行的脚本,如果让它运行得足够长,将消耗我系统上的所有内存.

没有详细介绍脚本,我有两个问题:

  1. 是否有任何"最佳实践"可以帮助防止泄漏发生?
  2. 有哪些技术可以调试Python中的内存泄漏?

Chr*_*heD 99

看看这篇文章:跟踪python内存泄漏

另请注意,垃圾收集模块实际上可以设置调试标志.看看这个set_debug功能.另外,请查看Gnibbler的此代码,以确定调用后创建的对象类型.


lin*_*nqu 77

我尝试了之前提到的大多数选项,但发现这个小而直观的包是最好的:pympler

跟踪非垃圾收集的对象非常简单,请查看以下小例子:

通过安装包 pip install pympler

from pympler.tracker import SummaryTracker
tracker = SummaryTracker()

# ... some code you want to investigate ...

tracker.print_diff()
Run Code Online (Sandbox Code Playgroud)

输出显示已添加的所有对象以及它们消耗的内存.

样本输出:

                                 types |   # objects |   total size
====================================== | =========== | ============
                                  list |        1095 |    160.78 KB
                                   str |        1093 |     66.33 KB
                                   int |         120 |      2.81 KB
                                  dict |           3 |       840 B
      frame (codename: create_summary) |           1 |       560 B
          frame (codename: print_diff) |           1 |       480 B
Run Code Online (Sandbox Code Playgroud)

该软件包提供了许多其他功能.检查pympler的文档,特别是识别内存泄漏一节.

  • 值得注意的是,`pympler`可以**慢慢**.如果您正在半实时地做某事,它可能会完全削弱您的应用程序性能. (3认同)

Den*_*kov 22

让我推荐mem_top工具,
这有助于我解决类似的问题.

它只是立即显示Python程序中内存泄漏的最大嫌疑人.

  • @me_,我刚刚添加了"使用"的下一步,添加了"计数器"部分,添加了解释为什么Gearman确实是该现实生活中的嫌疑人,在代码中记录了"mem_top()"的每个可选参数,并将此全部上传为v0.1.7 - 请查看是否还有其他改进措施.谢谢!) (4认同)
  • 这是真的……但它对使用/结果解释的方式很少 (2认同)

use*_*491 15

Tracemalloc模块作为内置模块集成,从Python 3.4开始,显然,它也可用于以前版本的Python作为第三方库(尽管尚未测试).

该模块能够输出分配最多内存的精确文件和行.恕我直言,这些信息无疑比每种类型的分配实例的数量更有价值(99%的时间最终会成为很多元组,这是一个线索,但在大多数情况下几乎没有帮助).

我建议你将tracemalloc与pyrasite结合使用.10次​​中的9次,在pyrasite-shell中运行前10个片段将为您提供足够的信息和提示,以便在10分钟内修复泄漏.然而,如果您仍然无法找到泄漏原因,pyrasite-shell与此线程中提到的其他工具相结合可能会给您更多提示.您还应该查看pyrasite提供的所有额外帮助程序(例如内存查看器).


Jue*_*gen 11

您应该专门查看全局或静态数据(长寿命数据).

当这些数据不受限制地增长时,您也可能在Python中遇到麻烦.

垃圾收集器只能收集不再引用的数据.但是您的静态数据可以连接应该释放的数据元素.

另一个问题可能是内存周期,但至少从理论上讲,垃圾收集器应该找到并消除周期 - 至少只要它们没有挂在一些长期的生存数据上.

什么样的长寿数据特别麻烦?仔细查看任何列表和词典 - 它们可以不受限制地增长.在字典中,您甚至可能看不到麻烦,因为当您访问dicts时,字典中的键数可能对您来说不是很大的可见性......


小智 7

要检测和定位长时间运行的进程的内存泄漏,例如在生产环境中,您现在可以使用stackimpact.它使用下面的tracemalloc.这篇文章中的更多信息.

在此输入图像描述


The*_*man 5

至于最佳实践,请留意递归函数。就我而言,我遇到了递归问题(不需要的地方)。我在做什么的一个简化示例:

def my_function():
    # lots of memory intensive operations
    # like operating on images or huge dictionaries and lists
    .....
    my_flag = True
    if my_flag:  # restart the function if a certain flag is true
        my_function()

def main():
    my_function()
Run Code Online (Sandbox Code Playgroud)

以这种递归方式操作不会触发垃圾收集并清除函数的剩余部分,因此每次通过内存使用量都在增长。

我的解决方案是将递归调用从 my_function() 中提取出来,并让 main() 处理何时再次调用它。这样函数自然结束并自行清理。

def my_function():
    # lots of memory intensive operations
    # like operating on images or huge dictionaries and lists
    .....
    my_flag = True
    .....
    return my_flag

def main():
    result = my_function()
    if result:
        my_function()
Run Code Online (Sandbox Code Playgroud)

  • 如果达到递归深度限制,以这种方式使用递归也会中断,因为 Python 不会优化尾调用。默认情况下,这是 1000 次递归调用。 (7认同)