moo*_*eep 4 python garbage-collection
请考虑以下脚本:
l = [i for i in range(int(1e8))]
l = []
import gc
gc.collect()
# 0
gc.get_referrers(l)
# [{'__builtins__': <module '__builtin__' (built-in)>, 'l': [], '__package__': None, 'i': 99999999, 'gc': <module 'gc' (built-in)>, '__name__': '__main__', '__doc__': None}]
del l
gc.collect()
# 0
Run Code Online (Sandbox Code Playgroud)
关键是,在所有这些步骤之后,我的机器上的这个python进程的内存使用率大约是30%(Python 2.6.5,请求的更多细节?).这是top的输出的摘录:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
5478 moooeeeep 20 0 2397m 2.3g 3428 S 0 29.8 0:09.15 ipython
Run Code Online (Sandbox Code Playgroud)
RESP.ps aux:
moooeeeep 5478 1.0 29.7 2454720 2413516 pts/2 S+ 12:39 0:09 /usr/bin/python /usr/bin/ipython gctest.py
Run Code Online (Sandbox Code Playgroud)
根据该文档为gc.collect:
并非某些免费列表中的所有项目都可能因特定实现而被释放,特别是
int和float.
这是否意味着,如果我(暂时)需要大量的不同int或float数字,我需要将其导出到C/C++,因为Python GC无法释放内存?
更新
正如本文所暗示的那样,解释器可能是罪魁祸首:
这是你同时创建了500万个整数,每个int对象消耗12个字节."为了速度",Python维护整数对象的内部空闲列表.不幸的是,这个免费清单既是不朽的,也是无限的.花车也使用不朽的无限列表.
然而问题仍然存在,因为我无法避免这些数据(来自外部源的时间戳/值对).我真的被迫放弃Python并回到C/C++吗?
更新2
可能确实是这样,Python实现会导致问题.找到这个答案最终解释了问题和可能的解决方法.
我做了一些测试,这个问题只发生在CPython 2.x. 这个问题在CPython 3.2.2中消失了(它回到了新解释器的内存使用情况),而PyPy 1.8(python 2.7.2)也降低到了与新的pypy进程相同的水平.
所以不,你不需要切换到另一种语言.但是,可能有一种解决方案不会强制您切换到不同的Python实现.
发现这也是Alex Martelli在另一个帖子中回答的问题.
不幸的是(取决于你的版本和Python版本),某些类型的对象使用"自由列表",这是一个简洁的局部优化但可能导致内存碎片,特别是通过为特定类型的对象创建更多的内存"专用"和从而无法获得"普通基金".
确保大量但临时使用内存的唯一真正可靠的方法是在完成后将所有资源返回给系统,就是在子进程中使用该进程,这会占用大量内存,然后终止工作.在这种情况下,操作系统将完成其工作,并乐意回收子进程可能已经吞噬的所有资源.幸运的是,多处理模块在现代版本的Python中进行这种操作(过去相当痛苦)并不算太糟糕.
在您的用例中,似乎子进程积累一些结果并确保主进程可用的结果的最佳方法是使用半临时文件(半临时文件,我的意思是,不是那种文件,关闭时会自动消失,只有当你完成它们时才明确删除的普通文件).
幸运的是,我能够将内存密集型工作拆分为单独的块,使得解释器在每次迭代后实际释放临时内存.我使用以下包装器作为子进程运行内存密集型函数:
import multiprocessing
def run_as_process(func, *args):
p = multiprocessing.Process(target=func, args=args)
try:
p.start()
p.join()
finally:
p.terminate()
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4670 次 |
| 最近记录: |