python中for循环的内存分配
Posted
技术标签:
【中文标题】python中for循环的内存分配【英文标题】:Memory allotment of for loop in python 【发布时间】:2015-08-10 18:53:54 【问题描述】:我对 python 对函数的内存使用感到困惑。 我正在运行一个函数,其中返回 pandas 数据帧 (1161 X 240),参数为 (bamfile, pandas.Dataframe(1161 X 50))。
现在我将通过分析器给出内存使用情况:
Line # Mem usage Increment Line Contents
================================================
120 983.363 MiB 0.000 MiB @profile
121 def overlapping_peaks_distribution(bam_peak1, overlap_df):
122 '''
123 Returns dataframe for tag count distribution for overlapping peaks within 500bp (+,-) from summit.
124 This function also considers the gene transcrition direction.
125 :param bam_peak1:
126 :param overlap_df:
127 :return:
128 '''
129 983.363 MiB 0.000 MiB import pandas as pd
130 983.363 MiB 0.000 MiB import sys
131 983.363 MiB 0.000 MiB peak_distribution_sample = pd.DataFrame()
132 983.363 MiB 0.000 MiB print 'Process: Feature extraction from BAM started'
133 1783.645 MiB 800.281 MiB for ind, row in overlap_df.iterrows():
134 1782.582 MiB -1.062 MiB sys.stdout.write("\rFeature extraction for peak:%d" % ind)
135 1782.582 MiB 0.000 MiB sys.stdout.flush()
136 1782.582 MiB 0.000 MiB chr = str(row['chr'])
137 1782.582 MiB 0.000 MiB orientation = row['Next transcript strand']
138 1782.582 MiB 0.000 MiB middle = row['start'] + row['summit']
139 1782.582 MiB 0.000 MiB start = middle - 3000
140 1782.582 MiB 0.000 MiB stop = start + 50
141 1782.582 MiB 0.000 MiB list_sample1 = []
142 #total_tags = int(bam_peak1.mapped) will get total no of mapped reads
143
144 1782.586 MiB 0.004 MiB for i in range(0, 120):
145 1782.586 MiB 0.000 MiB tags1 = bam_peak1.count(chr, start, stop)
146 1782.586 MiB 0.000 MiB start = stop
147 1782.586 MiB 0.000 MiB stop = start + 50 # divide peaks into length of 25 bp
148 1782.586 MiB 0.000 MiB list_sample1.append(tags1)
149 1782.586 MiB 0.000 MiB if orientation > 0: # Direction gene transcription
150 #print 'Towards 5 prime'
151 1780.883 MiB -1.703 MiB peak_distribution_sample = peak_distribution_sample.append(pd.Series(list_sample1), ignore_index=True)
152 else:
153 #print 'Towards 3 prime'
154 1783.645 MiB 2.762 MiB peak_distribution_sample = peak_distribution_sample.append(pd.Series(list_sample1[::-1]), ignore_index=True)
155 #print peak_distribution_sample
156 1783.645 MiB 0.000 MiB return peak_distribution_sample
我不明白为什么在 第 133 行 会增加 800MB(疯狂)。这占用了我记忆中的所有空间。不知道这是不是我的错?
我使用对象图来查找内存泄漏。 函数启动前的对象数:
(Pdb) objgraph.show_most_common_types()
function 15293
tuple 4115
dict 3086
cell 2670
list 2107
weakref 1834
wrapper_descriptor 1760
builtin_function_or_method 1655
getset_descriptor 1235
type 1232
函数完成后的对象数。
(Pdb) import objgraph
(Pdb) objgraph.show_growth()
function 16360 +1067
dict 3546 +460
list 2459 +354
tuple 4414 +306
getset_descriptor 1508 +273
builtin_function_or_method 1895 +240
weakref 2049 +215
module 593 +123
wrapper_descriptor 1877 +117
type 1341 +109
我们可以看到对象的显着增加。 我还制作了一些图表。
我相信 红色字体框应该被释放,但它们没有。
【问题讨论】:
很有可能overlap_df.iterrows()
在开始第一次迭代之前将其完全加载到内存中。
github.com/pydata/pandas/issues/7683
这可能是个问题,但如何释放该内存。
【参考方案1】:
您确定它没有显示overlap_df
的总大小吗?
这里有类似的东西:
144 1782.586 MiB 0.004 MiB for i in range(0, 120):
Profiler 将 120 个整数列表的总大小显示为 400 KB。
【讨论】:
这意味着overlap_df的大小为800MB。这是不可能的,因为在物理内存上它需要 8MB 的空间。我在每次迭代时都读到它分配内存但不释放它。最后函数完成打印 out_of_memory()。我也试过 gc.collect() 但它没有效果。嵌套循环使情况变得更糟。【参考方案2】:我发现了内存泄漏。这是因为第三方模块 (pysam) 存在内存泄漏。
【讨论】:
以上是关于python中for循环的内存分配的主要内容,如果未能解决你的问题,请参考以下文章