当前位置: 首页 > 面试题库 >

JNA / ByteBuffer无法释放并导致C堆内存不足

阎冠玉
2023-03-14
问题内容

首先,我对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”块之间存在间隙。解决方案是分配大于所需大小的恒定大小的块。



 类似资料:
  • 我在C#上度过了一段糟糕的时光,在我不再引用它之后,没有为我保存在内存中的大型结构释放内存。 我在下面包含了一些代码,它们显示了与我遇到的问题类似的问题。我想我一定是误解了GC,因为我不确定为什么下面的代码会抛出内存不足异常。 有人知道为什么我包含的代码会丢失内存吗?没有一份名单被保留,可以立即清理。 谢谢, 保罗 复制:全新的4.5控制台应用程序,将代码粘贴到Main中。 异常将在for循环的第

  • 问题内容: 我正在运行django应用程序,其中包括matplotlib,并允许用户指定图形的轴。这可能会导致 “溢出错误:超出了Agg复杂度” 发生这种情况时,最多会占用100MB的RAM。通常,我会使用,和释放该内存,但是与该错误关联的内存似乎与该绘图对象无关。 有谁知道我该如何释放记忆? 谢谢。 这是一些给我Agg复杂度错误的代码。 问题答案: 我假设您可以至少运行一次您发布的代码。该问题仅

  • 本文向大家介绍c# 从内存中释放Selenium chromedriver.exe,包括了c# 从内存中释放Selenium chromedriver.exe的使用技巧和注意事项,需要的朋友参考一下 背景 我设置了一个c#代码来运行Selenium chromedriver.exe.在运行结束时,我有browser.close()来关闭实例。(browser = webdriver.Chrome(

  • > 指向自动分配实例的指针是否可以使该实例即使在实例化的作用域被保留后也不被解除分配? <罢工> 在 我读到的这篇文章说所有指向去分配内存的指针都是无效的。 但这家伙说的是手动解锁还是自动解锁后的行为? 这是一个示例:

  • 我对C#中的单例模式在C++中释放对象内存有一个困惑;这里是C++代码: 当我使用rocket::close()时,ms_rocket指向的内存空间将被释放,ms_rocket变成一个野指针,第二个“cout 在C#中,我认为当我使用Dispose()时,内存(B单例中的'a'对象)会被释放,但在第二次访问中,age值不应该是100,静态变量'a'会变得像野指针一样。谁能告诉我为什么?

  • 我得到一个奇怪的内存不足错误解码一个可绘制的图像资源960x926px jpg,分配3555856字节。图像仅放置在drawable-xxhdpi(3x)中,而我使用的是hdpi(1.5x)设备。两个问题: > 为什么堆中有足够的空闲内存却出现错误? 03-18 17:30:15.050 327 50-32750/?D/DALVIKVM:GC_FOR_ALLOC释放10809K,49%释放2373