Mik*_*ike 1 python garbage-collection memory-management
我需要按顺序读取大文本文件,将大量数据存储在内存中,然后使用它们编写大文件.这些读/写周期一次完成一个,并且没有公共数据,因此我不需要在它们之间共享任何内存.
我尝试将这些过程放在一个脚本中,希望垃圾收集器在RAM满了时删除旧的,不再需要的对象.但事实并非如此.即使我在循环之间明确删除了对象,也需要比单独运行程序要长得多.
具体来说,该过程将挂起,使用所有可用的RAM,但几乎没有CPU.gc.collect()被召唤时它也挂了.因此,我决定将每个读/写过程拆分为单独的脚本,并使用中央脚本调用它们execfile().遗憾的是,这并没有解决任何问题.记忆仍然堆积如山.
我使用了简单明了的解决方案,即从shell脚本调用下标而不是使用execfile().但是,我想知道是否有办法使这项工作.有什么输入?
任何没有引用的CPython对象都会立即被释放.Python会定期执行垃圾收集,以处理仅相互引用但程序无法访问的对象组(循环引用).如果需要在特定时间完成,可以手动调用垃圾收集器来清除它们(gc.collect()).这使得内存可供Python脚本重用,但可能会立即(或曾经)将内存释放回操作系统.
CPython在256KB竞技场中分配内存,它将其划分为4KB池,这些池进一步细分为块,这些块被指定用于特定大小的对象(这些通常是相似类型但不一定是).此内存可以在Python进程中重用,但在整个竞技场为空之前不会释放回操作系统.
现在,在2005年之前,一些常用的对象类型没有使用这种方案.例如,一旦创建了'int'或'float',即使它被Python释放,该内存也永远不会返回给操作系统,但它可以重用于这些类型的其他对象.(当然小ints是共享的,不占用任何额外的内存,但如果你分配了一个大ints或floats 的列表,即使在释放这些对象之后,CPython也会保留该内存.)Python还保留了由列表和词典分配的一些内存(例如最近的80个列表).
这完全是根据本文档关于Python内存分配器大约版本2.3的改进.我知道从那时起已经做了一些进一步的工作,所以一些细节可能已经改变了(根据arbautjc的评论已经纠正了int/ float情况)但是基本情况仍然存在:出于性能原因,Python没有将所有内存都返回到操作系统立即,因为malloc()小分配的开销相对较高,而内存碎片越多,速度越慢.因此,Python只有mallocs()大量的内存块,并在这些块本身内部分配内存,并且只有在完全为空时才将这些块返回给操作系统.
您可以尝试其他Python实现,例如PyPy(旨在尽可能与CPython兼容),Jython(在JVM上运行)或IronPython(在.NET CLR上运行)以查看它们的内存管理是否更加复杂.你在做.如果您当前使用的是32位Python,则可以尝试使用64位Python(假设您的CPU和操作系统支持它).
但是,从shell脚本顺序调用脚本的方法对我来说似乎完全没问题.您可以使用该subprocess模块在Python中编写主脚本,但它在shell中可能更简单.
但是,如果不了解您的脚本正在做什么,很难猜出造成这种情况的原因.