gpt4 book ai didi

java - JNA/ByteBuffer 未被释放并导致 C 堆内存不足

转载 作者:搜寻专家 更新时间:2023-10-30 21:25:21 25 4
gpt4 key购买 nike

首先让我说,我对 JNA 和 Java 如何直接进行 native 内存分配的理解充其量只是本能的,所以我试图描述我对正在发生的事情的理解。除了回复之外的任何更正都会很棒......

我正在运行一个使用 JNA 混合 Java 和 C native 代码的应用程序,并且在运行时遇到一个可重现的问题,即 Java 垃圾收集器未能释放对直接 native 内存分配的引用,导致 C 堆内存不足。

我肯定我的 C 应用程序不是分配问题的根源,因为我将 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 堆,但没有清理指向该内存的 ByteBuffer,因为 Java ByteBuffer 对象相对较小。

到目前为止,我发现在我的函数中手动运行 GC 将提供所需的清理,但这似乎既是一个糟糕的主意,也是一个糟糕的解决方案。

如何更好地管理这个问题,以便适当释放 ByteBuffer 空间并控制我的 C 堆空间?

我对问题的理解是否不正确(我运行不正确)?

编辑:调整缓冲区大小以更反射(reflect)我的实际应用,我分配给大约 3000x2000 的图像...

最佳答案

你实际上面对的是a known bug in the Java VM .错误报告中列出的最佳解决方法是:

  • “-XX:MaxDirectMemorySize= 选项可用于限制使用的直接内存量。尝试分配直接内存会导致超过此限制会导致完全 GC,从而引发引用处理和释放未引用的缓冲区。”

其他可能的解决方法包括:

  • 偶尔插入显式 System.gc() 调用以确保回收直接缓冲区。
  • 减小年轻代的大小以强制更频繁地进行 GC。
  • 在应用程序级别显式池化直接缓冲区。

如果您真的想依赖直接字节缓冲区,那么我建议在应用程序级别进行池化。根据您的应用程序的复杂性,您甚至可以简单地缓存和重用相同的缓冲区(注意多线程)。

关于java - JNA/ByteBuffer 未被释放并导致 C 堆内存不足,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1744533/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com