gpt4 book ai didi

python - 调试 Python/NumPy 内存泄漏

转载 作者:太空狗 更新时间:2023-10-30 01:34:29 58 4
gpt4 key购买 nike

我正在尝试使用 C/Cython 扩展和 多处理 查找 Python/NumPy 程序中严重内存泄漏的根源。

每个子进程处理一个图像列表,并通过 Queue 将每个子进程的输出数组(通常大约 200-300MB 大)发送到主进程。相当标准的 map/reduce 设置。

正如您可以想象的那样,对于这么大的数组,内存泄漏会占据巨大的比例,并且让多个进程在它们只需要 5-6GB 内存的情况下愉快地使用超过 20GB RAM 是......很烦人。

  • 我已尝试通过 Valgrind 运行 Python 的调试版本,并四次检查我的扩展是否存在内存泄漏,但一无所获。

  • 我已经检查了我的 Python 代码是否存在对我的数组的悬挂引用,并且还使用了 NumPy 的 allocation tracker检查我的数组是否确实已发布。他们是。

我做的最后一件事是将 GDB 附加到我的一个进程(这个坏男孩现在正在以 27GB RAM 运行并且还在计数)并将大部分堆转储到磁盘。令我惊讶的是,转储文件中全是零!大约7G的零。

这是 Python/NumPy 中的标准内存分配行为吗?我是否遗漏了一些明显的东西,可以解释为什么有这么多内存没有用?如何正确管理内存?


编辑:为了记录,我正在运行 NumPy 1.7.1 和 Python 2.7.3。

编辑 2: 我一直在用 strace 监控进程,它似乎一直在增加每个进程的断点(使用 brk() 系统调用)。

CPython 是否真的正确地释放了内存? C 扩展、NumPy 数组怎么样?谁决定何时调用 brk(),是 Python 本身还是底层库(libc,...)?

下面是一个带有评论的示例 strace 日志,来自一次迭代(即一个输入图像集)。请注意,断点不断增加,但我确保(使用 objgraph)没有有意义的 NumPy 数组保留在 Python 解释器中。

# Reading .inf files with metadata
# Pretty small, no brk()
open("1_tif_all/AIR00642_1.inf", O_RDONLY) = 6
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9387fff000
munmap(0x7f9387fff000, 4096) = 0
open("1_tif_all/AIR00642_2.inf", O_RDONLY) = 6
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9387fff000
munmap(0x7f9387fff000, 4096) = 0
open("1_tif_all/AIR00642_3.inf", O_RDONLY) = 6
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9387fff000
munmap(0x7f9387fff000, 4096) = 0
open("1_tif_all/AIR00642_4.inf", O_RDONLY) = 6
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9387fff000
munmap(0x7f9387fff000, 4096) = 0

# This is where I'm starting the heavy processing
write(2, "[INFO/MapProcess-1] Shot 642: Da"..., 68) = 68
write(2, "[INFO/MapProcess-1] Shot 642: Vi"..., 103) = 103
write(2, "[INFO/MapProcess-1] Shot 642: Re"..., 66) = 66

# I'm opening a .tif image (752 x 480, 8-bit, 1 channel)
open("1_tif_all/AIR00642_3.tif", O_RDONLY) = 6
read(6, "II*\0JC\4\0", 8) = 8
mmap(NULL, 279600, PROT_READ, MAP_SHARED, 6, 0) = 0x7f9387fbb000
munmap(0x7f9387fbb000, 279600) = 0
write(2, "[INFO/MapProcess-1] Shot 642: Pr"..., 53) = 53

# Another .tif
open("1_tif_all/AIR00642_4.tif", O_RDONLY) = 6
read(6, "II*\0\266\374\3\0", 8) = 8
mmap(NULL, 261532, PROT_READ, MAP_SHARED, 6, 0) = 0x7f9387fc0000
munmap(0x7f9387fc0000, 261532) = 0
write(2, "[INFO/MapProcess-1] Shot 642: Pr"..., 51) = 51
brk(0x1aea97000) = 0x1aea97000

# Another .tif
open("1_tif_all/AIR00642_1.tif", O_RDONLY) = 6
read(6, "II*\0\220\253\4\0", 8) = 8
mmap(NULL, 306294, PROT_READ, MAP_SHARED, 6, 0) = 0x7f9387fb5000
munmap(0x7f9387fb5000, 306294) = 0
brk(0x1af309000) = 0x1af309000
write(2, "[INFO/MapProcess-1] Shot 642: Pr"..., 53) = 53
brk(0x1b03da000) = 0x1b03da000

# Another .tif
open("1_tif_all/AIR00642_2.tif", O_RDONLY) = 6
mmap(NULL, 345726, PROT_READ, MAP_SHARED, 6, 0) = 0x7f9387fab000
munmap(0x7f9387fab000, 345726) = 0
brk(0x1b0c42000) = 0x1b0c42000
write(2, "[INFO/MapProcess-1] Shot 642: Pr"..., 51) = 51

# I'm done reading my images
write(2, "[INFO/MapProcess-1] Shot 642: Fi"..., 72) = 72

# Allocating some more arrays for additional variables
# Increases by about 8M at a time
brk(0x1b1453000) = 0x1b1453000
brk(0x1b1c63000) = 0x1b1c63000
brk(0x1b2473000) = 0x1b2473000
brk(0x1b2c84000) = 0x1b2c84000
brk(0x1b3494000) = 0x1b3494000
brk(0x1b3ca5000) = 0x1b3ca5000

# What are these mmap calls doing here?
mmap(NULL, 270594048, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9377df1000
mmap(NULL, 270594048, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9367be2000
mmap(NULL, 270594048, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f93579d3000
mmap(NULL, 270594048, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f93477c4000
mmap(NULL, 270594048, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f93375b5000
munmap(0x7f93579d3000, 270594048) = 0
munmap(0x7f93477c4000, 270594048) = 0
mmap(NULL, 270594048, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f93579d3000
munmap(0x7f93375b5000, 270594048) = 0
mmap(NULL, 50737152, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9354970000
munmap(0x7f9354970000, 50737152) = 0
brk(0x1b4cc6000) = 0x1b4cc6000
brk(0x1b5ce7000) = 0x1b5ce7000

编辑 3: Is freeing handled differently for small/large numpy arrays?可能是相关的。我越来越确信我只是分配了太多未释放到系统的数组,因为它确实是标准行为。将尝试预先分配我的数组并根据需要重用它们。

最佳答案

呵呵。我真的应该第五次检查那些 C 扩展。

我忘记减少我从 C 分配的一个临时 NumPy 数组中的引用计数。该数组没有离开 C 代码,所以我没有看到我需要释放它。

我仍然不知道为什么它没有出现在 objgraph 中。

关于python - 调试 Python/NumPy 内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18964821/

58 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com