numpy.ndarray 个对象未被垃圾回收
numpy.ndarray objects not garbage collected
在尝试微调某些 C/C++ 函数的 Python 绑定中的一些内存泄漏时,我遇到了一些与 Numpy 数组的垃圾收集有关的奇怪行为。
为了更好地解释行为,我创建了几个简化的案例。代码是 运行 使用 memory_profiler
,其输出紧随其后。对于 NumPy 数组,Python 的垃圾收集似乎没有按预期工作:
# File deallocate_ndarray.py
@profile
def ndarray_deletion():
import numpy as np
from gc import collect
buf = 'abcdefghijklmnopqrstuvwxyz' * 10000
arr = np.frombuffer(buf)
del arr
del buf
collect()
y = [i**2 for i in xrange(10000)]
del y
collect()
if __name__=='__main__':
ndarray_deletion()
通过以下命令我调用了 memory_profiler
:
python -m memory_profiler deallocate_ndarray.py
这是我得到的:
Filename: deallocate_ndarray.py
Line # Mem usage Increment Line Contents
================================================
5 10.379 MiB 0.000 MiB @profile
6 def ndarray_deletion():
7 17.746 MiB 7.367 MiB import numpy as np
8 17.746 MiB 0.000 MiB from gc import collect
9 17.996 MiB 0.250 MiB buf = 'abcdefghijklmnopqrstuvwxyz' * 10000
10 18.004 MiB 0.008 MiB arr = np.frombuffer(buf)
11 18.004 MiB 0.000 MiB del arr
12 18.004 MiB 0.000 MiB del buf
13 18.004 MiB 0.000 MiB collect()
14 18.359 MiB 0.355 MiB y = [i**2 for i in xrange(10000)]
15 18.359 MiB 0.000 MiB del y
16 18.359 MiB 0.000 MiB collect()
我不明白为什么即使强制调用 collect
也不会通过释放一些内存来减少程序的内存使用。此外,即使 Numpy 数组由于底层 C 构造而不能正常运行,为什么列表(纯 Python)没有被垃圾收集?
我知道 del
不会直接调用底层的 __del__
方法,但是你会注意到代码中的所有 del
语句实际上最终都会减少引用计数相应的对象为零(从而使它们有资格进行垃圾收集 AFAIK)。通常,当对象进行垃圾回收时,我希望在增量列中看到一个负条目。任何人都可以阐明这里发生的事情吗?
注意:此测试是在 OS X 10.10.4、Python 2.7.10 (conda)、Numpy 1.9.2 (conda)、Memory Profiler 0.33 (康达宾星),psutil 2.2.1(康达)。
为了查看收集的内存垃圾,我不得不将 buf 的大小增加几个数量级。也许大小太小 memory_profiler
无法检测到变化(它查询 OS,因此测量不是很精确)或者它太小 Python 垃圾收集器无法关心,我不知道。
例如,在因子 buf
中用 100000000 替换 10000 得到
Line # Mem usage Increment Line Contents
================================================
21 10.289 MiB 0.000 MiB @profile
22 def ndarray_deletion():
23 17.309 MiB 7.020 MiB import numpy as np
24 17.309 MiB 0.000 MiB from gc import collect
25 2496.863 MiB 2479.555 MiB buf = 'abcdefghijklmnopqrstuvwxyz' * 100000000
26 2496.867 MiB 0.004 MiB arr = np.frombuffer(buf)
27 2496.867 MiB 0.000 MiB del arr
28 17.312 MiB -2479.555 MiB del buf
29 17.312 MiB 0.000 MiB collect()
30 17.719 MiB 0.406 MiB y = [i**2 for i in xrange(10000)]
31 17.719 MiB 0.000 MiB del y
32 17.719 MiB 0.000 MiB collect()
在尝试微调某些 C/C++ 函数的 Python 绑定中的一些内存泄漏时,我遇到了一些与 Numpy 数组的垃圾收集有关的奇怪行为。
为了更好地解释行为,我创建了几个简化的案例。代码是 运行 使用 memory_profiler
,其输出紧随其后。对于 NumPy 数组,Python 的垃圾收集似乎没有按预期工作:
# File deallocate_ndarray.py
@profile
def ndarray_deletion():
import numpy as np
from gc import collect
buf = 'abcdefghijklmnopqrstuvwxyz' * 10000
arr = np.frombuffer(buf)
del arr
del buf
collect()
y = [i**2 for i in xrange(10000)]
del y
collect()
if __name__=='__main__':
ndarray_deletion()
通过以下命令我调用了 memory_profiler
:
python -m memory_profiler deallocate_ndarray.py
这是我得到的:
Filename: deallocate_ndarray.py
Line # Mem usage Increment Line Contents
================================================
5 10.379 MiB 0.000 MiB @profile
6 def ndarray_deletion():
7 17.746 MiB 7.367 MiB import numpy as np
8 17.746 MiB 0.000 MiB from gc import collect
9 17.996 MiB 0.250 MiB buf = 'abcdefghijklmnopqrstuvwxyz' * 10000
10 18.004 MiB 0.008 MiB arr = np.frombuffer(buf)
11 18.004 MiB 0.000 MiB del arr
12 18.004 MiB 0.000 MiB del buf
13 18.004 MiB 0.000 MiB collect()
14 18.359 MiB 0.355 MiB y = [i**2 for i in xrange(10000)]
15 18.359 MiB 0.000 MiB del y
16 18.359 MiB 0.000 MiB collect()
我不明白为什么即使强制调用 collect
也不会通过释放一些内存来减少程序的内存使用。此外,即使 Numpy 数组由于底层 C 构造而不能正常运行,为什么列表(纯 Python)没有被垃圾收集?
我知道 del
不会直接调用底层的 __del__
方法,但是你会注意到代码中的所有 del
语句实际上最终都会减少引用计数相应的对象为零(从而使它们有资格进行垃圾收集 AFAIK)。通常,当对象进行垃圾回收时,我希望在增量列中看到一个负条目。任何人都可以阐明这里发生的事情吗?
注意:此测试是在 OS X 10.10.4、Python 2.7.10 (conda)、Numpy 1.9.2 (conda)、Memory Profiler 0.33 (康达宾星),psutil 2.2.1(康达)。
为了查看收集的内存垃圾,我不得不将 buf 的大小增加几个数量级。也许大小太小 memory_profiler
无法检测到变化(它查询 OS,因此测量不是很精确)或者它太小 Python 垃圾收集器无法关心,我不知道。
例如,在因子 buf
中用 100000000 替换 10000 得到
Line # Mem usage Increment Line Contents
================================================
21 10.289 MiB 0.000 MiB @profile
22 def ndarray_deletion():
23 17.309 MiB 7.020 MiB import numpy as np
24 17.309 MiB 0.000 MiB from gc import collect
25 2496.863 MiB 2479.555 MiB buf = 'abcdefghijklmnopqrstuvwxyz' * 100000000
26 2496.867 MiB 0.004 MiB arr = np.frombuffer(buf)
27 2496.867 MiB 0.000 MiB del arr
28 17.312 MiB -2479.555 MiB del buf
29 17.312 MiB 0.000 MiB collect()
30 17.719 MiB 0.406 MiB y = [i**2 for i in xrange(10000)]
31 17.719 MiB 0.000 MiB del y
32 17.719 MiB 0.000 MiB collect()