JNA / ByteBuffer无法释放并导致C堆内存不足
首先,我对JNA和Java如何直接本机内存分配的理解充其量只是内在的,因此,我试图描述我对正在发生的事情的理解。除了回应以外的任何更正都会很棒。
我正在运行一个使用JNA混合Java和C本机代码的应用程序,并且遇到了一个可重现的问题,Java垃圾收集器无法释放对直接本机内存分配的引用,导致C堆内存不足。
我很肯定我的C应用程序不是分配问题的根源,因为我将A传递java.nio.ByteBuffer
到我的C代码中,修改了缓冲区,然后在Java函数中访问了结果。在每个函数调用期间,我只有一个malloc
和一个对应项free
,但是在Java中反复运行代码后,malloc最终将失败。
这是显示问题的一些琐碎代码集- 实际上,我正在函数调用期间尝试在C堆上分配大约16-32MB 。
我的Java代码执行以下操作:
public class MyClass{ public void myfunction(){
ByteBuffer foo = ByteBuffer.allocateDirect(1000000);
MyDirectAccessLib.someOp(foo, 1000000);
System.out.println(foo.get(0));
}
}
public MyDirectAccessLib{
static {
Native.register("libsomelibrary");
}
public static native void someOp(ByteBuffer buf, int size);
}
然后我的C代码可能类似于:
#include <stdio.h>#include <stdlib.h>
void someOp(unsigned char* buf, int size){
unsigned char *foo;
foo = malloc(1000000);
if(!foo){
fprintf(stderr, "Failed to malloc 1000000 bytes of memory\n");
return;
}
free(foo);
buf[0] = 100;
}
麻烦的是,在反复调用此函数之后,Java堆有些稳定(增长缓慢),但是C函数最终无法分配更多的内存。在较高的层次上,我认为这是因为Java正在为C堆分配内存,但是由于Java
ByteBuffer对象相对较小,因此并未清除指向该内存的ByteBuffer。
到目前为止,我发现在我的函数中手动运行GC将提供所需的清除,但是这似乎既不是一个好主意,也是一个糟糕的解决方案。
如何更好地管理此问题,以便适当地释放ByteBuffer空间并控制C堆空间?
我对问题的理解是否不正确(是否运行不正确)?
:调整缓冲区大小以更能反映我的实际应用,我为图像分配大约3000x2000 …
回答:
我认为您已正确诊断:您永远不会用完Java堆,因此JVM不会进行垃圾回收,并且不会释放映射的缓冲区。手动运行GC时没有问题的事实似乎证实了这一点。您还可以打开详细的收集日志记录作为辅助确认。
所以,你可以做什么?好吧,我首先要尝试使用-
Xms命令行参数将初始JVM堆大小保持较小。如果您的程序不断在Java堆上分配少量内存,则可能会导致问题,因为它会更频繁地运行GC。
我还将使用 pmap
工具(或Windows上的任何等效工具)来检查虚拟内存映射。您可能会通过分配可变大小的缓冲区来碎片化C堆。如果真是这样,那么您会看到每张更大的虚拟地图,其中“
anon”块之间存在间隙。解决方案是分配大于所需大小的恒定大小的块。
以上是 JNA / ByteBuffer无法释放并导致C堆内存不足 的全部内容, 来源链接: utcz.com/qa/399813.html