有没有什么方法可以释放生成的java代码中的内存来通过JNI / JNA绑定C代码?

我正在使用一个使用JNA绑定到原始C库的Java库(该库名为Leptonica)。 我遇到了一种情况,必须在C代码中调用free(data)来释放内存。 但是,java中是否有任何可以释放内存的function?

在C代码中

void ImageData::SetPixInternal(Pix* pix, GenericVector* image_data) { l_uint8* data; size_t size; pixWriteMem(&data, &size, pix, IFF_PNG); pixDestroy(&pix); image_data->init_to_size(size, 0); memcpy(&(*image_data)[0], data, size); free(data); } 

函数pixWriteMem()将为“数据”创建和分配内存,您需要自由(数据)以便以后释放内存。

在Java代码中,我只能访问pixWriteMem(),而不能访问SetPixInternal(),所以我无法释放“数据”,这会造成内存泄漏。

这里的其他评论和答案似乎都暗示你只是依赖垃圾收集器或告诉垃圾收集器运行。 对于在C中分配并通过JNI在Java中使用的内存,这不是正确的答案。

看起来execution() 确实释放了内存。 您向我们展示的最后一行是free(data) 。 不过,为了回答你提出的问题,答案是“不直接”。 如果您能够添加到C代码,则可以创建另一个C函数来释放数据,然后使用JNI调用它。 也许还有更多我们没有看到哪些更好地与您对内存泄漏的关注有关?

另外,请注意释放您正在使用的库分配的内存。 在尝试释放它之前,您应该确保库不需要它并且正在泄漏它。

现在回到内存管理一般……

Java确实是一种垃圾收集语言。 这意味着您没有专门删除对象。 相反,您确保没有对它的引用,然后垃圾收集器负责内存管理。 这并不意味着Java没有内存泄漏,因为有些方法可能会意外地保留引用,以便对象永远不会被垃圾回收。 如果你有这种情况,你可能想要阅读Java中的不同类型的引用(强/弱/等) 。

同样,这不是问题。 这是一个C / Java混合,有问题的代码是由Java调用的。 在C中,您分配了要使用的内存,然后在完成后需要自己free内存。 即使C代码是通过JNI由Java运行的, 您仍然要对自己的内存负责 。 你不能只是malloc()一堆内存,并希望Java垃圾收集器知道何时清理它。 因此OP的问题。

如果您需要自己添加function以free ,即使没有C部分的源代码,如果您可以访问指向相关内存的指针,您仍可以编写自己的C接口来释放内存。 您可以编写一个基本上只为您释放内存的小型库,为它创建JNI接口,并将指针传递给它。 如果你走这条路,那么根据你的操作系统,你可能需要保证你的微小的免费库的本机代码在与其他本机代码相同的进程中运行,或者如果不是相同的进程那么至少那个进程你运行它有对其他代码进程拥有的内存的写访问权限; 在你的情况下,这个内存/进程问题可能不是问题,但为了完整性,我把它丢弃了。

在Java代码中,我只能访问createData(),而不能执行excution(),因此我无法释放“数据”,这会造成内存泄漏。

然后它很难成为你。

说真的,如果你想释放由本机方法分配的内存并且在该方法返回之前没有释放,那么你需要在该内存上维护某种句柄,然后将其传递给另一个释放内存的本机方法。 如果您目前没有可用的本机方法,那么您需要创建一个。

另一个问题是如何确保调用所需的本机方法。 如果用户不这样做,依靠用户直接或间接地调用它会让你对内存泄漏开放。 有两种主要方法可以解决这个问题:

  • 给你的类一个终结器,确保释放内存。 这是终结器的核心用例,但即使如此,也有充分的理由希望避免编写它们。 另一种选择是

  • 创建引用对象( SoftReferenceWeakReferencePhantomReference ),将引用与用于释放属于引用的Java对象(但不通过该对象)的本机分配的内存的机制相关联,并将该对象注册到引用队列。 当对象是GC时,引用将被排队,此时您知道释放本机分配的内存。

这并不一定意味着您应该阻止用户明确释放内存,因为有足够的簿记,您可以跟踪是否仍需要在任何给定时间释放任何内容。 允许用户明确释放资源可能有助于降低整体资源使用率。 但是如果你想避免内存泄漏,那么你需要有一个后备。

没有像Java的Free()这样的函数。 但你可以建议通过调用System.gc()来运行垃圾收集器