JavaCPP Leptonica:如何清除 pixClone 句柄的内存

JavaCPP Leptonica : How to clear memory of pixClone handles

直到现在,我一直使用 pixDestroy 来清理我的 JavaCPP/Leptonica 应用程序中的 PIX 对象。然而,我最近注意到一个奇怪的内存泄漏问题,我追踪到内部返回 pixClone 结果的 Leptonica 函数。我设法通过使用以下简单测试重现了该问题:

    @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 的句柄:

Notes:

  1. A "clone" is simply a handle (ptr) to an existing pix. It is implemented because (a) images can be large and hence expensive to copy, and (b) extra handles to a data structure need to be made with a simple policy to avoid both double frees and memory leaks. Pix are reference counted. The side effect of pixClone() is an increase by 1 in the ref count.

  2. The protocol to be used is: (a) Whenever you want a new handle to an existing image, call pixClone(), which just bumps a ref count. (b) Always call pixDestroy() on all handles. This decrements the ref count, nulls the handle, and only destroys the pix when pixDestroy() has been called on all handles.

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

作为对函数 returns 它接收一个指针作为参数的常见情况的优化,JavaCPP 也 returns JVM 的相同对象。 pixClone() 就是这样。它只是 returns 用户作为参数传递的指针,因此 imgclone 最终都引用了 Java.

中的同一个对象

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

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

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