【发布时间】:2017-06-13 03:14:00
【问题描述】:
我有一段代码接收来自另一个函数的回调并创建一个列表列表 (pd_arr)。然后使用此列表创建数据框。最后列表列表被删除。
在使用内存分析器进行分析时,这是输出
102.632812 MiB 0.000000 MiB init()
236.765625 MiB 134.132812 MiB add_to_list()
return pd.DataFrame()
394.328125 MiB 157.562500 MiB pd_df = pd.DataFrame(pd_arr, columns=df_columns)
350.121094 MiB -44.207031 MiB pd_df = pd_df.set_index(df_columns[0])
350.292969 MiB 0.171875 MiB pd_df.memory_usage()
350.328125 MiB 0.035156 MiB print sys.getsizeof(pd_arr), sys.getsizeof(pd_arr[0]), sys.getsizeof(pd_df), len(pd_arr)
350.328125 MiB 0.000000 MiB del pd_arr
在检查 pd_df(数据帧)的深内存使用情况时,它是 80.5 MB。所以,我的问题是为什么在del pd_arr 行之后内存没有减少。
此外,根据分析器 (157 - 44 = 110 MB) 的总数据帧大小似乎超过 80 MB。那么,造成这种差异的原因是什么?
此外,是否有任何其他节省内存的方法来创建数据帧(循环接收的数据),这在时间性能上并不算太差(例如:对于大小为 100MB 的数据帧,增加 10 秒应该没问题)?
编辑:解释此行为的简单 python 脚本
Filename: py_test.py
Line # Mem usage Increment Line Contents
================================================
9 102.0 MiB 0.0 MiB @profile
10 def setup():
11 global arr, size
12 102.0 MiB 0.0 MiB arr = range(1, size)
13 131.2 MiB 29.1 MiB arr = [x+1 for x in arr]
Filename: py_test.py
Line # Mem usage Increment Line Contents
================================================
21 131.2 MiB 0.0 MiB @profile
22 def tearDown():
23 global arr
24 131.2 MiB 0.0 MiB del arr[:]
25 131.2 MiB 0.0 MiB del arr
26 93.7 MiB -37.4 MiB gc.collect()
关于引入数据框,
Filename: py_test.py
Line # Mem usage Increment Line Contents
================================================
9 102.0 MiB 0.0 MiB @profile
10 def setup():
11 global arr, size
12 102.0 MiB 0.0 MiB arr = range(1, size)
13 132.7 MiB 30.7 MiB arr = [x+1 for x in arr]
Filename: py_test.py
Line # Mem usage Increment Line Contents
================================================
15 132.7 MiB 0.0 MiB @profile
16 def dfCreate():
17 global arr
18 147.1 MiB 14.4 MiB pd_df = pd.DataFrame(arr)
19 147.1 MiB 0.0 MiB return pd_df
Filename: py_test.py
Line # Mem usage Increment Line Contents
================================================
21 147.1 MiB 0.0 MiB @profile
22 def tearDown():
23 global arr
24 #del arr[:]
25 147.1 MiB 0.0 MiB del arr
26 147.1 MiB 0.0 MiB gc.collect()
【问题讨论】:
-
您是否完全确定代码中的其他任何地方都没有对
pd_arr的引用? Python 是引用计数的,因此使用del只会释放关联的内存,前提是可以确保无法从任何地方使用已删除的对象。也可以试试clear the list。 -
我尝试使用
del pd_arr[:]。没有减少内存。 pd_arr 在代码中被定义为全局。那会有什么不同吗? -
好吧,
del pd_arr只是意味着您不能再使用名称pd_arr来引用该列表,无论是否是全局的,但如果在以前的某个时间点有类似a = pd_arr的东西(尽管它可能更微妙,比如将pd_arr传递给函数并将其引用复制到其他地方),那么它不会被真正删除。但是,我无法解释为什么del pd_arr[:]没有任何区别。 -
没有其他指向 pd_arr 的引用指针。