pru*_*tal 5 python garbage-collection memory-leaks memory-management memory-profiling
在尝试为某些 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()
Run Code Online (Sandbox Code Playgroud)
使用以下命令,我调用了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()
Run Code Online (Sandbox Code Playgroud)
我不明白为什么即使是强制调用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 (conda-binstar)、psutil 2.2.1 (conda) 上运行。
为了查看回收的内存垃圾,我必须将 buf 的大小增加几个数量级。也许大小太小而无法memory_profiler检测到更改(它会查询操作系统,因此测量结果不是很精确),或者可能太小以至于 Python 垃圾收集器无法关心,我不知道。
例如,将因子buf收益率中的 10000 替换为 100000000
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()
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
493 次 |
| 最近记录: |