Python内存泄漏

Python内存泄漏,python,debugging,memory-management,memory-leaks,Python,Debugging,Memory Management,Memory Leaks,我有一个长时间运行的脚本,如果让它运行足够长的时间,它将消耗我系统上的所有内存 在不详细介绍脚本的情况下,我有两个问题: 是否有任何有助于防止泄漏发生的“最佳实践”可供遵循 Python中有哪些技术可以调试内存泄漏 看看这篇文章: 另外,请注意,实际上可以设置调试标志。查看set\u debug功能。此外,请查看以确定调用后创建的对象的类型。不确定python中内存泄漏的“最佳实践”,但python应该通过垃圾收集器清除自己的内存。因此,我将首先检查一些短数据的循环列表,因为它们不会被垃圾收集器

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

在不详细介绍脚本的情况下,我有两个问题:

  • 是否有任何有助于防止泄漏发生的“最佳实践”可供遵循
  • Python中有哪些技术可以调试内存泄漏

  • 看看这篇文章:


    另外,请注意,实际上可以设置调试标志。查看
    set\u debug
    功能。此外,请查看以确定调用后创建的对象的类型。

    不确定python中内存泄漏的“最佳实践”,但python应该通过垃圾收集器清除自己的内存。因此,我将首先检查一些短数据的循环列表,因为它们不会被垃圾收集器拾取。

    您应该特别查看您的全局或静态数据(长寿命数据)

    当这些数据无限制地增长时,在Python中也会遇到麻烦

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

    另一个问题可能是内存周期,但至少在理论上,垃圾收集器应该找到并消除周期——至少只要它们不依赖于一些长期存在的数据


    什么样的长寿命数据特别麻烦?仔细查看任何列表和词典——它们可以无限增长。在字典中,您甚至可能看不到问题的出现,因为当您访问dicts时,字典中的键数对您来说可能不是很明显……

    这绝不是详尽的建议。但是,为了避免将来的内存泄漏(循环),写作时要记住的第一件事是确保任何接受回调引用的东西都应该将该回调存储为弱引用。

    让我推荐我创建的工具

    它帮助我解决了一个类似的问题


    它立即显示了Python程序中内存泄漏的主要嫌疑犯

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

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

    通过
    pip安装pympler安装软件包

    from pympler.tracker import SummaryTracker
    tracker = SummaryTracker()
    
    # ... some code you want to investigate ...
    
    tracker.print_diff()
    
    输出将显示已添加的所有对象,以及它们所消耗的内存

    样本输出:

                                     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
    

    此软件包提供了更多功能。检查,特别是章节。

    就最佳实践而言,注意递归函数。在我的例子中,我遇到了递归问题(不需要递归)。我正在做的一个简单示例:

    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()
    
    以这种递归方式操作不会触发垃圾收集并清除函数的剩余部分,因此每次内存使用量都在不断增长

    我的解决方案是从我的函数()中提取递归调用,并在再次调用它时使用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()
    

    要检测和定位长时间运行的进程(例如在生产环境中)的内存泄漏,您现在可以使用。它在下面使用。更多信息请访问

    从Python 3.4开始作为一个内置模块集成,显然,它也可用于Python as的早期版本(但尚未测试)

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


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

    或对永久保存的对象的引用,你们能提供一些永久保存的循环列表和对象的例子吗?我发现这很有用。它看起来打印出来的数据太多了useful@Casebash:如果该函数打印任何内容,则表明您的操作严重错误。它列出了使用
    \uuuu del\uuu
    方法的对象,这些对象除了其循环之外不再被引用。由于
    \uu del\uu
    的问题,无法中断该循环。修好它!可能与之重复值得注意的是,
    pympler
    可能会很慢。如果你在做一些半实时的事情,它会完全削弱你的应用程序性能。@sebpiq奇怪的是,同样的情况也发生在我身上。。。你知道为什么会这样吗?快速查看源代码并没有给出真正的见解。如果达到递归深度限制,以这种方式使用递归也会有所突破,因为Python不会优化尾部调用。默认情况下,这是1000个递归调用。。。但它在使用/结果方面提供的信息很少explanation@me_,此工具同时记录了“用法”和“解释结果”部分。我是否应该添加这样的解释:“refs是来自对象的引用数,types是这种类型的对象数,bytes是对象的大小”-记录这一点不是太明显了吗?该工具的使用文档给出了一行文字:“不时:logging.debug(mem_top())”,虽然它的解释结果是作者的真实生活中的错误跟踪经验没有上下文。。。这不是一个技术规范,告诉开发人员他们正在看什么。。。我不是在敲你的答案。。。它显示了账单上的高级别嫌疑人。。。它没有提供足够的文档