Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/315.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 调试JVM内存泄漏_Java_C++_Memory Leaks_Jvm_Java Native Interface - Fatal编程技术网

Java 调试JVM内存泄漏

Java 调试JVM内存泄漏,java,c++,memory-leaks,jvm,java-native-interface,Java,C++,Memory Leaks,Jvm,Java Native Interface,我有一个Java应用程序,它使用本机库实现一些功能。它使用JNI控制本机库,还接收来自库的异步回调。您可以将其视为相互通信的Java前端和本机后端 我正面临内存泄漏。启动应用程序后不久,内存缓慢但稳定地增加。所以我试着看看是什么导致了泄漏 首先,我尝试用一个简单的C++文本接口来代替java前端。这样,应用程序就不会以任何方式使用Java,泄漏也就停止了。所以问题一定出在Java前端 因此,我启动了jvisualVM来查看堆是否增加了,结果却没有。Java堆的大小相当稳定。我甚至用xmx32m启

我有一个Java应用程序,它使用本机库实现一些功能。它使用JNI控制本机库,还接收来自库的异步回调。您可以将其视为相互通信的Java前端和本机后端

我正面临内存泄漏。启动应用程序后不久,内存缓慢但稳定地增加。所以我试着看看是什么导致了泄漏

首先,我尝试用一个简单的C++文本接口来代替java前端。这样,应用程序就不会以任何方式使用Java,泄漏也就停止了。所以问题一定出在Java前端

因此,我启动了jvisualVM来查看堆是否增加了,结果却没有。Java堆的大小相当稳定。我甚至用xmx32m启动了这个程序,但是内存一直在增加,超过了100m,没有任何
OutOfMemoryError
s。事实上,jvisualVM显示Java堆大约为700万

所以我更深入地研究了WinDbg的项目。我用
分析了堆模式!heap-s
命令,我得到了以下结果:

新运行程序上的堆:

0:059> !heap -s
LFH Key                   : 0x382288b9
Termination on corruption : ENABLED
  Heap     Flags   Reserv  Commit  Virt   Free  List   UCR  Virt  Lock  Fast 
                    (k)     (k)    (k)     (k) length      blocks cont. heap 
-----------------------------------------------------------------------------
00330000 00000002    2048   1704   2048     22    71     2    0      0   LFH
005b0000 00001002    1088    212   1088     68     3     2    0      0   LFH
00aa0000 00001002    1088    108   1088     15     7     2    0      0   LFH
004f0000 00001002   15424  12876  15424   1372    89     9    0      1   LFH
...

0:059> !heap -stat -h 004f0000
 heap @ 004f0000
group-by: TOTSIZE max-display: 20
    size     #blocks     total     ( %) (percent of total busy bytes)
    2b110 20 - 562200  (60.36)
    98 166e - d5150  (9.33)
    6cd20 1 - 6cd20  (4.77)
    ...
已运行约半小时的程序上的堆:

0:046> !heap -s
LFH Key                   : 0x5e47ba72
Termination on corruption : ENABLED
  Heap     Flags   Reserv  Commit  Virt   Free  List   UCR  Virt  Lock  Fast 
                    (k)     (k)    (k)     (k) length      blocks cont. heap 
-----------------------------------------------------------------------------
006b0000 00000002    2048   1744   2048     46    92     2    0      0   LFH
00200000 00001002    1088    220   1088     68     3     2    0      0   LFH
00950000 00001002    1088    108   1088     15     7     2    0      0   LFH
001b0000 00001002   47808  31936  47808   1855   102    12    0      0   LFH
...

0:046> !heap -stat -h 001b0000
 heap @ 001b0000
group-by: TOTSIZE max-display: 20
    size     #blocks     total     ( %) (percent of total busy bytes)
    98 59d1 - 355418  (36.67)
    2b110 10 - 2b1100  (29.61)
    6cd20 1 - 6cd20  (4.68)
    ...
现在可以清楚地看到,泄漏是由越来越多的尺寸为98的砌块造成的。但是当我试图用
分析其中一个块时!heap-p-a
,我得到:

***错误:找不到符号文件。默认为导出jvm.dll的符号

没有任何堆栈跟踪。因此,这些块被分配到jvm.dll中的某个地方,因为jvm没有pdb,所以我无法进一步调试泄漏

我设法查明了代码中泄漏的位置。Java前端的所有调用都通过一个函数传递:

void callback(JNIEnv *env, int stream, double value, char *callbackName){
    jclass jni = env->FindClass("nativ/Callbacks");
    jmethodID callbackMethodID = env->GetStaticMethodID(jni, callbackName, "(ID)V");
    jvalue params[2];
    params[0].i = (long)(stream);
    params[1].d = value;
    env->CallStaticVoidMethodA(jni, callbackMethodID, params); //commenting this out stops the leaks
}
当我注释掉最后一个命令时,泄漏停止,但我没有得到反馈给前端


这可能是JVM错误吗?如何找到答案?

malloc()在内部调用HeapAlloc()。我想您需要一个“Release”方法来释放JVM分配的内存,只要您的库保持对JVM内部状态的引用。

Windows堆是一个旧API。大多数malloc()实现都不使用它们。@brian您能详细说明一下吗?然后使用哪些其他API?这是如何解释我在Windbg输出中看到的增加的呢?我所看到的所有malloc()都使用VirtualAlloc()。如果堆的增长与进程大小的增长相匹配,那么就是一些使用windows堆的API。