leptonica - JavaCPP Leptonica:如何清除 pixClone 句柄的内存
问题描述
到目前为止,我一直使用pixDestroy来清理我的 JavaCPP/Leptonica 应用程序中的 PIX 对象。然而,我最近注意到一个奇怪的内存泄漏问题,我追踪到 Leptonica 函数在内部返回一个 pixClone 结果。我设法通过使用以下简单测试重现了该问题:
@Test
public void test() throws InterruptedException {
String pathImg = "...";
for (int i = 0; i < 100; i++) {
PIX img = pixRead(pathImg);
PIX clone = pixClone(img);
pixDestroy(clone);
pixDestroy(img);
}
Thread.sleep(10000);
}
当达到 Thread.sleep 时,Windows 任务管理器中的 RAM 内存使用量(不是堆大小)已增加到大约 1GB,并且在睡眠结束和测试完成之前不会释放。
查看pixClone的文档,我们看到它实际上创建了现有 PIX 的句柄:
笔记:
“克隆”只是现有像素的句柄(ptr)。它的实现是因为 (a) 图像可能很大,因此复制成本很高,并且 (b) 需要使用简单的策略对数据结构进行额外的处理,以避免双重释放和内存泄漏。Pix 是引用计数的。pixClone() 的副作用是引用计数增加 1。
要使用的协议是: (a) 每当您想要一个现有图像的新句柄时,调用 pixClone(),它只会增加一个引用计数。(b) 始终在所有句柄上调用 pixDestroy()。这会减少引用计数,使句柄为空,并且仅在对所有句柄调用 pixDestroy() 时才销毁 pix。
如果我理解正确,我确实在所有句柄上调用 pixDestroy,所以引用计数应该达到零,因此 PIX 应该被销毁。显然,情况并非如此。有人可以告诉我我做错了什么吗?提前致谢!
解决方案
作为对函数返回作为参数接收的指针的常见情况的优化,JavaCPP 也将相同的对象返回给 JVM。这就是正在发生的事情pixClone()
。它只是返回用户作为参数传递的指针,因此两者img
最终clone
都引用了 Java 中的同一个对象。
现在,当pixDestroy()
在第一个引用上调用时img
,Leptonica 有用地将其地址重置为 0,但我们现在丢失了地址,第二次调用pixDestroy()
接收到该空指针,导致无操作和内存泄漏。
避免此问题的一种简单方法是PIX
在每次调用 之后显式创建一个新引用pixClone()
,例如,在这种情况下:
PIX clone = new PIX(pixClone(img));
推荐阅读
- python - 如何使用 1d 数组搜索 2d 数组以返回 2d 数组的索引 1
- c# - 有没有办法从 Bot Framework 机器人发送 GroupMe 的图像或位置附件?
- javascript - 错误的链接,错误的地方
- angularjs - 如何在 Jasmine 中对 $uibModal 进行单元测试?(单元测试注入库)
- php - Laravel API JSON 请求更改属性名称
- php - 在 laravel 中将“历史数据”存储到数据库中的正确方法是什么?
- java - 如何使用 PDF OCR 批量处理文件?
- powershell - 移动项目失败,移动没有出现在目标目录中没有错误
- android - 添加“com.google.android.gms:play-services-location:17.0.0”库时出错
- javascript - Chart.js 仅在按下 f12 后显示