使用pandas和pickle进行Python内存分配

4

我正在运行一个 Python 脚本,可以粗略地概括为如下(半伪代码):

import pandas as pd
for json_file in json_files:
    with open(json_file,'r') as fin:
        data = fin.readlines()
    data_str = '[' + ','.join(x.strip() for x in data) + ']'
    df = pd.read_json(data_str)
    df.to_pickle('%s.pickle' % json_file)
    del df, data, data_str

该过程通过迭代创建数据框,并将每个数据框保存到一个唯一的文件中。然而,在该过程中我的内存似乎被使用完了,就好像del df, data, data_str不会释放内存(最初,我没有在代码中包括del语句,但我希望添加它可以解决这个问题——但实际上并没有)。在每次迭代中,大约相同数量的数据被读入数据框,大约占用我可用内存的3%;随着进程的迭代,每次迭代都会报告%MEM的3%增加(从我的终端中的ps u | grep [p]ython),最终我的内存被淹没,进程被杀死。我的问题是,我应该如何改变我的代码/方法,以便在每次迭代时,前一次迭代的内存得到释放?
需要注意的是,我正在运行Ubuntu 16.04,使用Anaconda下的Python 3.5.2。
感谢您提前的指导。

你是对的,在for循环中不需要使用del删除变量,因为每次变量在循环中重新绑定时,旧对象的引用计数都会减少。它们在for完成后仍然存在,但如果这是在函数中,那么该引用也会消失。我唯一的猜测是clean_json_to_str可能会做一些坏事,比如保留对对象的后台引用。 - tdelaney
非常感谢您的回答@tdelaney。我已经更新了我的问题,更明确了clean_json_to_str步骤,并坦诚地说明了我在del调用中所做的一切(尽管,正如您所提到的,这不应该是问题所在)。 - Tom
我创建了一个版本的你的代码,以便我可以测试在这里,并且它没有显示出奇怪的内存消耗。由于底层堆扩展并且在前几次迭代中有空闲可用空间,所以你可能会遇到一些颠簸。但是这会平衡掉,对我来说,没有内存增加。 - tdelaney
为什么要对基于JSON的数据框进行腌制?总的来说,腌制并不是一种内存高效的方法,对于基于JSON的对象来说有点多余。请参阅https://hbfs.wordpress.com/2013/01/08/python-memory-management-part-ii/ 了解腌制的详细信息。我建议只需将清理后的JSON保存在不同的文本文件中,并在需要时使用“json”模块进行读取即可。 - Munir
@tdelaney 感谢您的代码并对此进行研究。在我的端上,它表现得非常奇怪,与您的结果不符,这让我感到困惑。 - Tom
显示剩余2条评论
1个回答

2
在Python中,自动垃圾回收会释放变量(就像Python中的其他对象一样,pandas DataFrame也是它的一个对象)。有不同的垃圾回收策略可以进行调整(需要大量的学习)。
您可以使用以下命令手动触发垃圾回收:
import gc
gc.collect()

然而,频繁调用垃圾回收是不鼓励的,因为这是一项昂贵的操作,可能会影响性能。

参考资料


1
只有在简单的对象引用计数无法确定是否需要删除时(例如循环引用),才需要进行垃圾回收。它在OP的情况下并不需要,也无法解决问题。 - tdelaney

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接