首先,你肯定没有内存泄漏。如果每当接近 500MB 并且从未超过它时它就会“崩溃”,那么它就不可能泄漏。
我的猜测是你根本没有任何问题。
当 Python 的垃圾收集器清理东西时(通常在 CPython 中完成后立即发生),它通常不会实际将内存释放给操作系统。相反,它会保留它以备将来需要时使用。这是有意为之的——除非您破坏交换,否则重用内存比不断释放和重新分配内存要快得多。
另外,如果 500MB 是虚拟内存,那么在现代 64 位平台上这根本不算什么。如果它没有映射到物理/常驻内存(或者在计算机空闲时映射,但否则很快就被丢弃),那么这不是问题;只是操作系统对实际上免费的资源很好。
更重要的是:是什么让你认为存在问题?是否有任何实际症状,或者只是程序管理器/活动监视器/顶部/任何让您害怕的东西? (如果是后者,请查看其他程序。在我的 Mac 上,我当前有 28 个程序正在使用超过 400MB 的虚拟内存运行,并且我正在使用 16GB 中的 11 个,尽管虚拟内存不足 3GB实际上,如果我启动逻辑,那么内存的收集速度将快于逻辑使用它的速度;在那之前,操作系统为什么要浪费精力取消内存映射(特别是当它无法确保某些进程不会这样做时)去询问后来没有使用的内存)?
但如果有is一个真正的问题,有两种方法可以解决。
第一个技巧是在子进程中执行所有内存密集型操作,您可以杀死并重新启动以恢复临时内存(例如,通过使用multiprocessing.Process
or concurrent.futures.ProcessPoolExecutor
).
这通常会使事情变得更慢而不是更快。当临时内存主要是直接进入 GUI 的东西时,这显然不容易做到,因此必须驻留在主进程中。
另一种选择是找出内存的使用位置,而不是同时保留这么多对象。基本上,这有两个部分:
首先,在每个事件处理程序结束之前释放所有可能的内容。这意味着调用close
在文件上,或者del
ing 对象或将所有对它们的引用设置为None
, 呼叫destroy
在不可见的 GUI 对象上,最重要的是,不存储对不需要的东西的引用。 (你真的需要保留PhotoImage
使用后周围?如果这样做,有什么方法可以按需加载图像吗?)
接下来,确保您没有参考周期。在 CPython 中,只要不存在循环,垃圾就会立即清除,但如果有,它们会一直闲置,直到循环检查器运行。您可以使用gc module http://docs.python.org/3/library/gc.html调查此事。一件非常快速的事情就是经常尝试一下:
print(gc.get_count())
gc.collect()
print(gc.get_count())
如果您看到大幅下降,则说明存在周期。你必须向内看gc.getobjects()
and gc.garbage
,或附加回调,或只是推理您的代码以准确找到循环的位置。对于每一个,如果你真的不需要双向参考,那就去掉一个;如果这样做,请将其中一个更改为weakref
.