我有一个长期运行的脚本,如果我们足够长的时间运行,将消耗所有我的系统上的内存。
不深入有关脚本的详细信息,我有两个问题:
- 是否有任何“最佳实践”跟随,这将有助于防止泄漏的发生?
- 是什么技术有在Python调试内存泄漏?
我有一个长期运行的脚本,如果我们足够长的时间运行,将消耗所有我的系统上的内存。
不深入有关脚本的详细信息,我有两个问题:
看看这篇文章: 跟踪蟒蛇内存泄漏
另外,还要注意的是, 垃圾收集模块实际上可以有调试标志设置。 看看set_debug
功能。 另外,看看这段代码通过Gnibbler确定类型已在通话后创建的对象。
我尝试了前面提到的大多数选项,但发现这个小而直观的包装是最好的: pympler
这是相当直截了当地跟踪那些不垃圾收集的对象,看看这个小例子:
经由安装包pip install 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
这个软件包提供了一些更多的功能。 检查pympler的文档 ,尤其是部分识别内存泄漏 。
让我推荐mem_top工具,
,帮助我解决了类似的问题。
它只是即时显示在一个Python程序内存泄漏顶部的嫌疑人。
你应该专门对你的全局或静态数据看(长期居住数据)。
当这个数据的增长没有限制,你还可以得到麻烦在Python。
垃圾收集器只能收集数据,未提及任何更多。 但你的静态数据可以联播应该释放的数据元素。
另一个问题是存储周期,但至少在理论上,垃圾收集器应该找到并消除周期 - 至少只要他们不沉迷于一些长期居住数据。
什么样的生活长的数据是特别麻烦? 对任何列表和字典很好看 - 他们可以没有任何限制地扩大。 在词典中,你甚至可以不看,因为当您访问类型的字典的麻烦来了,钥匙在字典的数量可能不是很大的知名度,你的...
Tracemalloc模块被集成为在Python 3.4开始内置模块,并appearently,它也可用于Python的以前版本的第三方库 (没有测试过,虽然)。
该模块能够输出精确的文件和分配的大多数内存线。 恕我直言,这种信息infinitly比分配情况的每种类型的数量更有价值(这最终被大量的元组的时间,这是一个线索99%,但在大多数情况下,几乎没有帮助)。
我建议你结合使用tracemalloc与pyrasite 。 9次了10年,运行的前10段在pyrasite壳会给你足够的信息和提示,以在10分钟内修复泄漏。 然而,如果你仍然无法找到泄漏的原因,pyrasite壳与本主题中提到的其他工具的组合将可能给你一些更多的提示了。 你也应该采取由pyrasite提供的所有额外的帮助(比如内存查看器)看看。
为了检测和定位为长时间运行的进程的内存泄漏,例如在生产环境中,您现在可以使用stackimpact 。 它采用tracemalloc下方。 在更多信息这篇文章 。
不知道“最佳实践”为蟒蛇内存泄漏,但蟒蛇被它的垃圾收集器应该清除它自己的内存。 所以主要是我想通过检查一些短期的循环列表,因为它们不会被垃圾收集器被拾起启动。
这绝不是详尽的建议。 但一两件事以避免未来的内存泄漏(循环)的思想写作时要记住的是确保任何它接受一个回调的参考,应存储的回调视为弱引用。
至于最佳实践,保持眼睛的递归函数。 在我来说,我遇到了递归问题(这里有没有必要来定)。 我在做什么,一个简单的例子:
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()
在这种循环方式运行将不会触发垃圾收集和清除功能的遗体,所以通过内存使用量每次都是在不断扩张。
我的解决办法是拉递归调用了创建my_function()和主要有()处理时再调用它。 这样的功能自然结束后自己清理。
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()