OpenCV Python:如何避免 py3 中的 cv2.imwrite() 内存“泄漏”?

Posted

技术标签:

【中文标题】OpenCV Python:如何避免 py3 中的 cv2.imwrite() 内存“泄漏”?【英文标题】:OpenCV Python: how to avoid cv2.imwrite() memory "leak" in py3? 【发布时间】:2018-10-27 20:34:47 【问题描述】:

我正在调查在 Ubuntu 16.04 (x86) 上使用 OpenCV(3.4.1,本地构建)的 Python (3.5.2) 应用程序中的内存泄漏(或“膨胀”)。

应用程序经常将图像写入文件,并为此使用 .imwrite() 方法。我发现.imwrite() 的这种用法会导致 RAM 使用量激增,但我找不到这种行为的原因。

为了调试这个问题,我准备了这个简单的测试脚本:

#!/usr/bin/python3

import cv2
import time

img = cv2.imread("vista.jpg")

idx = 0
while True:
    filename = "/tmp/vista_copy_" + str(idx) + ".tiff"
    cv2.imwrite(filename, img)
    idx = idx + 1
    time.sleep(1)

在运行此脚本时,我监控了空闲 RAM(每 10 秒对空闲内存进行一次采样):

$ while [ 1 ] ; do grep MemFree /proc/meminfo ; sleep 10 ; done
MemFree:          898024 kB
MemFree:          780640 kB
MemFree:          667848 kB
MemFree:          545700 kB
MemFree:          437196 kB
MemFree:          315820 kB
MemFree:          298380 kB
MemFree:          298292 kB
MemFree:          297448 kB
MemFree:          297080 kB
MemFree:          915616 kB

最后一个样本,空闲内存恢复到初始值,是在我从目标中删除图像文件后拍摄的,这可能表明这是一个操作系统问题,或者文件没有​​被正确关闭程序(虽然我在 C++ 源代码中找不到这方面的线索)。 我觉得这种行为很奇怪,更是如此,因为 imwrite 是一种基本的方法。谁能帮忙调试和解决这个问题?

编辑 所以显然我的测试脚本中的内存消耗是由于 /tmp 实际上是一个 RAM 驱动器,但是当写入通过以太网适配器连接的外部驱动器时问题仍然存在。

更新 写入物理驱动器上的本地文件夹时会重现此问题。这似乎是与 imwrite 无关的一般操作系统问题。操作系统缓存文件,但永远不会释放这个缓存(也许它“认为”它有足够的内存来进行所有这些缓存)。 按照建议的here 和here 定期执行'echo 3 > /proc/sys/vm/drop_caches' 目前是一种合理的解决方法,但我们想要一个不那么侵入性/暴力的解决方案,它可以防止系统使用这么多缓存,或者可以让它不强制释放缓存。

【问题讨论】:

【参考方案1】:

看起来 /tmp 可能是某种 ramdisk 挂载,因此它可能会消耗 RAM,而不是磁盘空间,并在重新启动后清空。

https://wiki.archlinux.org/index.php/tmpfs

您可以通过针对不同目标文件夹测试您的脚本来确认这一点,例如将文件的存储定向到您的主目录。

【讨论】:

嗨@Micka,感谢您的回答。我想我的调试中有一个错误 :) 但是在写入外部磁盘时这个问题仍然存在。外部磁盘是通过网络适配器连接的,所以问题可能是类似的(数据缓存比传输快)?【参考方案2】:

OP 是绝对正确的。没有内存泄漏,但文件在写出时被缓存在内存中。尽管原则上您可以使用 os.posix_fadvise 之类的方法清除此缓存,但您需要 cv2 用于写入文件的句柄(而 CV2 API 不提供该句柄)。

理论上,通过清除缓存,操作系统/程序可以使用“缓存”内存。在实践中,这会减慢您的计算机速度,或者当您用 10k+ 小文件填满缓存时无法按预期工作(不幸的是,这恰好是我的用例)

【讨论】:

以上是关于OpenCV Python:如何避免 py3 中的 cv2.imwrite() 内存“泄漏”?的主要内容,如果未能解决你的问题,请参考以下文章

使用Python,OpenCV捕获关键事件,并进行视频剪辑

python3如何使用py3dns?

ROS——基于python3实现opencv图像处理任务(Melodic)

在Ubuntu14.04中安装Py3和切换Py2和Py3环境

在Ubuntu14.04中安装Py3和切换Py2和Py3环境

如何减少OpenCV python中的帧数?