【问题标题】:JavaCPP Leptonica : How to clear memory of pixClone handlesJavaCPP Leptonica:如何清除 pixClone 句柄的内存
【发布时间】:2019-11-12 07:22:52
【问题描述】:

直到现在,我一直使用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 的句柄:

注意事项:

  1. “克隆”只是现有像素的句柄 (ptr)。它的实现是因为 (a) 图像可能很大,因此成本很高 复制,并且 (b) 数据结构的额外句柄需要使用 避免双重释放和内存泄漏的简单策略。像素是 参考计数。 pixClone() 的副作用是增加 1 在引用计数中。

  2. 要使用的协议是: (a) 每当您想要现有图像的新句柄时,调用 pixClone(),它只会增加一个引用计数。 (二) 始终在所有句柄上调用 pixDestroy()。这会减少 ref 计数,使句柄为空,并且仅在 pixDestroy() 时销毁像素 已在所有句柄上调用。

如果我理解正确,我确实在所有句柄上调用 pixDestroy,所以引用计数应该达到零,因此 PIX 应该已经被销毁。显然,情况并非如此。有人可以告诉我我做错了什么吗?提前致谢!

【问题讨论】:

    标签: leptonica javacpp


    【解决方案1】:

    作为对函数返回作为参数接收的指针的常见情况的优化,JavaCPP 也将相同的对象返回给 JVM。这就是pixClone() 正在发生的事情。它只是返回用户作为参数传递的指针,因此 imgclone 最终都引用了 Java 中的同一个对象。

    现在,当 pixDestroy() 在第一个引用 img 上被调用时,Leptonica 有用地将其地址重置为 0,但我们现在丢失了地址,并且对 pixDestroy() 的第二次调用接收到该空指针,导致在 noop 和内存泄漏。

    避免此问题的一种简单方法是在每次调用 pixClone() 后显式创建一个新的 PIX 引用,例如,在这种情况下:

    PIX clone = new PIX(pixClone(img));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-05-10
      • 2021-12-24
      • 2014-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多