【问题标题】:JNA Memory LeakJNA 内存泄漏
【发布时间】:2012-03-05 15:44:18
【问题描述】:

鉴于此 C++ 代码:

void LoadData(char** myVar)
{
    std:: string str("[Really Long String Here]");
    unsigned int size = str.length() + 1;
    *myVar = new char[size];
    strncpy(*myVar, str.c_str(), size);
}

还有这个 JNA Java:

Pointer myVar = new Memory(Pointer.SIZE);
this.Lib.LoadData(myVar);
this.someVar = myVar.getPointer(0).getString(0);

我有内存泄漏,据我了解,getPointer(0) 应该创建一个指针对象,该对象应该在 finalize() 上释放,但似乎不是。

我错过了什么吗?这似乎符合规范......我可以运行上面的函数而不会在 C++ 中泄漏。

我在循环中调用 Java 代码来测试泄漏,我尝试过暂停,并手动调用 GC,这样它也会很快膨胀到千兆字节。

这几天我一直在努力解决这个问题,如果我试图释放内存这样微不足道的事情,我会感到很糟糕。据我所知,我只能在 Java 中手动释放内存有地址,但我不知道怎么弄到。

编辑:

没关系,我什至认为没有办法通过 JNA 手动释放而不扩展它...

【问题讨论】:

    标签: java c++ c jna


    【解决方案1】:

    将此函数添加到 C++ 库中...

    void FreeData(char** myVar)
    {
        delete [] *myVar;
    }
    

    然后将其设为 JNA 代码

    Pointer myVar = new Memory(Pointer.SIZE);
    this.Lib.LoadData(myVar);
    this.someVar = myVar.getPointer(0).getString(0);
    this.Lib.FreeData(myVar);
    

    这样你在 C++ 中分配和删除内存。

    【讨论】:

    • 到目前为止,这似乎可行,但是 JNA 中真的没有其他方法可以释放数据吗? :(
    • JNA 只是一个原生库的包装器。它不管理本机内存,尤其是直接本机缓冲区。本地库设计者的任务是提供接口来分配/释放库使用的内存。
    • JNA 确实有用于释放内存的内部方法,奇怪的是我不得不再次实现它,因为它都在 JNA 中受到保护。
    • @StrangeWill 可能是因为它的引用没有发布让GC接管stackoverflow.com/questions/1854398/…
    • 这就像使用 Windows Kernel32 的 HeapAlloc() 从堆中分配内存一样,我们需要使用 HeapFree() 释放它。如果我们在 C 中有一个内存分配函数,那么它也必须伴随着一个内存释放函数。
    【解决方案2】:

    在调用者中分配,而不是在被调用者中。

    例如:

    int LoadData(char* buf, int maxlen) {
        std:: string str("[Really Long String Here]");
        strncpy(buf, str.c_str(), maxlen);
        if (str.length() < maxlen) 
            return str.length();
        return maxlen;
    }
    

    然后,当您从 Java 调用时,传入适当大小的 byte[]。请注意,这种实现可能非常低效,但其想法是您通常不希望在一个上下文中分配内存并在另一个上下文中释放它。

    【讨论】:

    • 在实现中:char* buf 可以是 10 个字节、10k 或 150k,一旦我实现了完整的代码,可能会更多。除了分配几个兆并忍受低效的实现(我的软件可以,但我对使用 JNA 执行此操作的正确方法更感兴趣)。
    • 如果想让被调用者管理存储,可以返回一个“const char *”; JNA 会将内容复制到 Java 字符串中,之后您可以安全地修改缓冲区内容和/或删除它。如果返回Pointer,则可以避免内存复制,直到Java端真正需要查看数据。执行此操作的“正确”方法在很大程度上取决于程序的哪些部分(Java 或本机)需要访问数据、访问频率以及缓冲区的生存时间。
    【解决方案3】:

    而不是 myVar = 新字符[大小]

    使用

    *myVar = malloc(size);
    strncpy(*myVar, str.c_str(), size);
    

    需要删除数组,例如: 删除 [] *myVar;

    JNA prolly 不知道这样做。

    【讨论】:

    • 仍然泄漏,同样迅速。 :(
    猜你喜欢
    • 2018-05-09
    • 2016-01-23
    • 1970-01-01
    • 1970-01-01
    • 2011-10-08
    • 2013-01-20
    • 2011-10-31
    • 2019-08-10
    相关资源
    最近更新 更多