查找Java内存泄漏(使用JNA)

查找Java内存泄漏(使用JNA),java,memory,heap,jna,Java,Memory,Heap,Jna,我的Java应用程序似乎有内存泄漏。这是我第一次处理这样的事情。我不是使用纯Java,而是使用JNA来使用user32功能。 我注意到,当我的程序运行更长的时间(比如一小时)时,其进程所需的内存会不断增长。当我启动它时,它就像是100Mb,一个小时后它就超过了1Gb 我在使用windows任务管理器时注意到了这一点。当我开始研究这个问题时,我使用了像visualvm和JProfiler这样的分析器。两者都向我展示了大约150mb的堆使用量和大约20mb的PermGen空间,而windows任务管

我的Java应用程序似乎有内存泄漏。这是我第一次处理这样的事情。我不是使用纯Java,而是使用JNA来使用user32功能。 我注意到,当我的程序运行更长的时间(比如一小时)时,其进程所需的内存会不断增长。当我启动它时,它就像是100Mb,一个小时后它就超过了1Gb

我在使用windows任务管理器时注意到了这一点。当我开始研究这个问题时,我使用了像visualvm和JProfiler这样的分析器。两者都向我展示了大约150mb的堆使用量和大约20mb的PermGen空间,而windows任务管理器清楚地向我展示了它使用了大约1Gb的空间。所以我认为问题一定出在本机堆中,visualvm和JProfiler似乎都无法访问/profile。我创建了堆转储和内存快照,并用visualvm和MAT对它们进行了分析。最大的对象(以及它们保留的大小)从未超过4Mb——我根本不是专家,但这看起来不太容易泄漏/对我来说不太大。另外,当我手动垃圾收集(使用探查器)时,使用的java堆会像预期的那样变小,但进程的总消耗量保持在1Gb。这一发现还使我得出结论,问题不在Java堆空间内

所以我认为JNA调用导致了这个问题。但不幸的是,我不知道如何解决这个问题,因为我不能简单地不使用JNA。我读了大量关于内存泄漏的文章,其中大多数与jave有关,几乎总是忽略本机堆。那些没有的(例如oracle文章)告诉我,我不能简单地使用一种本机评测方法,因为它们误解了java代码并导致错误的结论。Oracle建议使用“libumem.so”,但这似乎只能在solaris系统上使用

所以,我的总体问题是——有人能给我一些关于该怎么做的提示吗?我可以使用什么工具

但问题可能只是我没有正确使用JNA。据此: 我从stackoverflow的几个文本片段中读到并理解到,互联网上的jna文档和随机文章是,jna将释放它分配的内存,java端分配的内存将被垃圾收集。因此,当我执行以下操作时:

    //I want to get text (as a String) of a handle
    public static String getTextOfHWND(HWND hwnd)
    {
      //allocate the space for the string
    byte[] windowText = new byte[512];
    //let user32 method fill me the byte array with the needed information
    User32.INSTANCE.SendMessageA(hwnd, WM_GETTEXT, 100, windowText);
    //let Native convert this to a String I can use in Java
    String whatWasFound = Native.toString(windowText);


    return whatWasFound;
    }
。。。GC应该释放“byte[]windowText”变量(为其分配的内存),该变量对于我得到的字符串(“whatWasFound”)应该有效。对吗?在这个例子中,我需要手动释放一些东西吗?我可以看到Native为缓冲区提供了一种免费的方法(但不幸的是,它不适用于数组)。在本机端发生了什么,是否在那里分配了一些内容,并且在之后发布了这些内容


感谢您的帮助。

这里有一些类似于
User32.INSTANCE.GetWindowText(hwnd、charBuf、charBuf.length)消除了对消息的需要
charBuf
char[]
。我不确定,但它可能更为unicode安全。我也有过这样的情况,我一直给dll函数一个32 MiB字节[],它用数据填充它(有点像你的),在60000次左右的调用后内存就用完了。我甚至不确定这是否是根本原因,因为我无法可靠地复制它。我将方法声明改为接受
内存
,但在实践中没有对其进行测试。当一个新的开发版本发布,人们使用它一段时间后,我们就可以确定这是否是问题所在(需要进一步研究…),或者它仍然可能是问题所在(不再崩溃,所以让我们保留内存)。@Mark Jeronimus我知道GetWindowText,但它在子句柄方面不如这个版本好。至少在我使用它的背景下。问题仍然存在——charBuf内存会发生什么?我将尝试使用内存而不是字节[],让我们看看它是否改变了什么。谢谢你的建议。在你的代码中寻找你调用本机方法返回缓冲区或其他本机分配内存的地方。在Java端创建的任何东西(
Memory
byte[]
)在不再被引用时都将被垃圾收集。JNA分配给自己使用的任何内存(结构、字符串数组等)也由GC管理。但是,如果您创建一组
内存
对象并维护对它们的引用,它们将不会被GC调用,它们所代表的本机内存将永远不会被释放(该内存对Java堆是不可见的)@technomage所以你认为用jna和user32.dll创建本机内存泄漏的唯一方法是保留对返回的缓冲区/内存的引用?其他任何东西都会被释放,我没有必要用手来释放?考虑到我从不自己分配任何东西——只使用java世界中的数组、整数和内存对象。