python - numpy.ndarray 对象未被垃圾收集

标签 python memory-management memory-leaks garbage-collection memory-profiling

在尝试为某些 C/C++ 函数微调 Python 绑定(bind)中的一些内存泄漏时,我遇到了一些与 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 (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()

关于python - numpy.ndarray 对象未被垃圾收集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31422150/

相关文章:

c - 在C中取消分配动态分配的结构内存

ios - 非常奇怪的崩溃,可能与 ARC 有关并且只出现在 iPhone 5s 上

python - 在 Debian Wheezy 上使用 flask-sqlalchemy 怪异的内存使用和泄漏

.net - 如何让 .NET 取消提交未使用的 RAM?

python - 以 3 为一组打印 python 列表

python - 使用 SymPy 通过给定点构造符号插值样条

python - 在 Pandas 数据框中加速 iloc 解决方案

Python 使用 SQLAlchemy 连接到 AWS Aurora Serverless MySQL

c - C 中结构指针的内存分配和核心转储

mysql - Matlab mysql jdbc 内存泄漏与数据库工具箱