【问题标题】:Python memory leakage and understanding profiler resultsPython 内存泄漏和了解分析器结果
【发布时间】:2022-10-08 22:31:57
【问题描述】:

我在带有数字标签的文件夹中有一组文件,我正在尝试整理和提取包含数据的统计信息。我的最小代码是:

import psutil as psutil
import sys as sys
import pandas as pd
import os as os
import glob as glob
import numpy as np
import matplotlib.pyplot as plt


@profile
def main():
    temp=[]
    strj=pd.DataFrame()

    ener_list=[]
    ref_ener_list=[]
    main_dir="./"
    column_list=["1","2","3","4","5","6","7"]
    f1_list=["part1","part2"]


    for folder in sorted(glob.iglob(main_dir+"/0????")):
        print(folder)
        print(psutil.Process().memory_info().rss / (1024 * 1024))
        for fld2 in sorted(glob.iglob(folder+"/run?????")):
            strj=pd.DataFrame()
            for fld1 in f1_list:
                for data_file in sorted(glob.iglob(fld2+"/prdv"+fld1+"/track.txt")):
                    temp=pd.read_table(data_file, comment="#",delim_whitespace=True,names=column_list)
                    strj=pd.concat([strj, temp])
                    del(temp)
            ener_list.append(strj.values.tolist())
            del(strj)
    print(np.shape(ener_list))

    avg_ener_list=(np.array(ener_list,dtype=object)).mean(axis=0)
    avg_ener_df=pd.DataFrame(avg_ener_list, columns=column_list)

    print(avg_ener_df,np.shape(avg_ener_df))

main()

exit()                                                     

对于整个数据集,我有 50 个文件夹和 1000 个子文件夹,每个子文件夹有 2 个部分。单个文件的大小可以是 5.6Kb(小)或 320Kb(大)。当我尝试在所有文件夹上运行我的代码时,我注意到我使用了超过 28GB 的​​内存,导致程序在数据提取部分进行到一半时被终止。我使用 memory_profiler 工具来跟踪内存泄漏,但我无法真正弄清楚我需要进行哪些更改。我在这种情况下缺乏经验,因为我以前不必处理内存问题。我也尝试跟踪变量使用的内存,但那里没有什么奇怪的。我在这里忽略了其他一些方面,还是应该改变我在这里提取数据的方式?

Line #    Mem usage    Increment  Occurrences   Line Contents
=============================================================
    23   99.961 MiB   99.961 MiB           1   @profile
    24                                         def main():
    25   99.961 MiB    0.000 MiB           1       temp=[]
    26   99.961 MiB    0.000 MiB           1       strj=pd.DataFrame()
    27
    28   99.961 MiB    0.000 MiB           1       ener_list=[]
    29   99.961 MiB    0.000 MiB           1       ref_ener_list=[]
    30   99.961 MiB    0.000 MiB           1       main_dir="./"
    31   99.961 MiB    0.000 MiB           1       column_list=["Step","Time","KE","Temp", "PE","TE","UsedTime"]
    32                                             #f_list=["part1","part2","part3"]
    33   99.961 MiB    0.000 MiB           1       f1_list=["part1","part2"]
    34   99.961 MiB    0.000 MiB           1       f2_list=["part1"]
    35
    36
    37 8065.902 MiB    0.000 MiB          10       for folder in sorted(glob.iglob(main_dir+"/0????")):
    38 7181.180 MiB    0.000 MiB           9           print(folder)
    39 7181.180 MiB    0.000 MiB           9           print(psutil.Process().memory_info().rss / (1024 * 1024))
    40 8065.902 MiB   -0.527 MiB        9009           for fld2 in sorted(glob.iglob(folder+"/run?????")):
    41 8065.020 MiB   -0.527 MiB        9000               strj=pd.DataFrame()
    42 8065.133 MiB   -4.262 MiB       27000               for fld1 in f1_list:
    43 8065.133 MiB   -3.449 MiB       36000                   for data_file in sorted(glob.iglob(fld2+"/prdv"+fld1+"/track.txt")):
    44                                                             #pass
    45 8066.078 MiB 9237.312 MiB       18000                       temp=pd.read_table(data_file, comment="#",delim_whitespace=True,names=column_list)
    46 8066.078 MiB -8199.547 MiB       18000                       strj=pd.concat([strj, temp])
    47 8065.133 MiB -16399.094 MiB       18000                       del(temp)
    48                                                             #strj=pd.concat([strj, pd.read_table(data_file, comment="#",delim_whitespace=True,names=column_list)])
    49                                                         #temp.append(pd.read_csv(data_file, delim_whitespace=True, skiprows=1))
    50 8065.902 MiB 6923.656 MiB        9000               ener_list.append(strj.values.tolist())
    51 8065.902 MiB   -0.270 MiB        9000               del(strj)
    52                                                 #print(sys.getsizeof(strj)/(1024*1024), sys.getsizeof(ener_list)/(1024*1024))
    53                                             #print(ener_list,np.shape(ener_list))
    54 8067.801 MiB    1.898 MiB           1       print(np.shape(ener_list))
    55
    56 8067.926 MiB    0.125 MiB           1       avg_ener_list=(np.array(ener_list,dtype=object)).mean(axis=0)
    57 8067.926 MiB    0.000 MiB           1       avg_ener_df=pd.DataFrame(avg_ener_list, columns=column_list)
    58
    59 8068.469 MiB    0.543 MiB           1       print(avg_ener_df,np.shape(avg_ener_df))

【问题讨论】:

  • 在赋值上使用del 实际上并不会释放内存——它只会减少分配给该名称的基础对象的引用计数器。您可能需要手动gc.collect(),请参阅thread。还有threadthread 与熊猫更相关。
  • @metatoaster 我尝试使用 gc.collect() 但我没有看到内存使用有任何重大变化。相反,相同大小的数据集的运行时间显着增加,代码变得不可用。同样在链接线程中,主要问题是显式调用 gc.collect() 通常不会提供任何重大更改。
  • 好吧,问题之一是ener_list 将随着您的代码读取更多文件而继续增长(并消耗内存),并且“临时”数据上的所有del 不太可能对您的情况有所帮助。尝试像这样注释掉所有相关的 append 以查看是否只是处理输入文件会导致问题,但如果您需要显式内存管理 Python 不是要使用的语言。
  • @metatoaster 注释掉 append 部分确实消除了内存问题并将使用的内存减少到 <5MiB。但奇怪的是ener_list 的大小只有 0.072 KiB(使用 getsizeof()),而 psutils 显示内存使用量高达 8GiB!所以我不确定多余的内存在哪里被使用......
  • ener_list 引用了 strj 内部的某些东西(通过strj.values.tolist()),这可能与原始内容有某种联系,从而使 numpy/pandas 内部的引用计数不被减少?搜索tolist 内存问题我遇到了this thread,所以可能是tolist 是内存泄漏的罪魁祸首。

标签: python memory memory-leaks profiling


【解决方案1】:

@metatoaster 的建议是正确的,因为 strj.values.tolist() 是导致内存泄漏的主要原因。因此,我没有使用数据帧列表,而是将我的数据结构更改为包含数据帧的dict()dict()。我目前的实现是:

import sys as sys
import pandas as pd
import os as os
import glob as glob
import gc as gc
import copy
import numpy as np

def read_raw(main_dir,name,fld1,column_list):
    cm_data_list=dict()
    data_list=dict()

    for item in column_list:
        data_list[item] = []
        cm_data_list[item] = []

    for folder in sorted(glob.iglob(main_dir+"/?????")):
        print(folder)
        for fld2 in sorted(glob.iglob(folder+"/run?????")):
            strj=pd.DataFrame()
            for fld1 in f1_list:
                for data_file in sorted(glob.iglob(fld2+"/"+name+fld1+"/track.txt")):
                    temp=pd.read_table(data_file, comment="#",delim_whitespace=True,names=column_list)
                    strj=pd.concat([strj, temp])
            for item in column_list:
                data_list[item].append((strj.loc[:,item]).values)
        copy_data=copy.deepcopy(data_list)
        cm_data_list=append_dict(cm_data_list,copy_data)
        data_list=clear_dict(data_list)
  return(cm_data_list)

main_dir=os.getcwd()
column_list=["1","2","3","4","5","6","7"]
f1_list=["part1","part2"]
print(read_raw(main_dir,"prdv",f1_list,column_list))

exit()

这显着减少了内存消耗。

【讨论】:

    猜你喜欢
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    • 2019-06-02
    • 1970-01-01
    • 2013-05-24
    • 1970-01-01
    • 1970-01-01
    • 2021-11-28
    相关资源
    最近更新 更多