在c++中new的对象,如果不返回java,必须用release掉,否则内存泄露。包括NewStringUTF,NewObject
。如果返回java不必release,java会自己回收。
jstring jstr = env->NewStringUTF((*p).sess_id);
...
env->DeleteLocalRef( jstr);
jobject jobj = env->NewObject(clazz,midInit);
return jobj;
内存泄露可以先从windows资源管理器中,看到随程序运行,内存不断增长的趋势,具体可以用hp jmeter检测。在运行程序时,加jvm参数 -Xrunhprof:heap=all,cutoff=0 ,生成java.hprof.txt,用jmeter打开,Metric -> Residual Objects (Count),可以看到未回收的对象,选中要查看的对象,点Mark记录下要查看的对象,Window -> New Window 打开新窗口,用Metric -> Reference Graph Tree,然后点Find Immediately可以看到对象被哪里引用。
找出内存泄漏另一方法
程序有内存泄漏的第一个迹象通常是它抛出一个 DE>OutOfMemoryErrorDE>,或者因为频繁的垃圾收集而表现出糟糕的性能。幸运的是,垃圾收集可以提供能够用来诊断内存泄漏的大量信息。如果以 DE>-verbose:gcDE> 或者 DE>-XloggcDE> 选项调用 JVM,那么每次 GC 运行时在控制台上或者日志文件中会打印出一个诊断信息,包括它所花费的时间、当前堆使用情况以及恢复了多少内存。记录 GC 使用情况并不具有干扰性,因此如果需要分析内存问题或者调优垃圾收集器,在生产环境中默认启用 GC 日志是值得的。
有工具可以利用 GC 日志输出并以图形方式将它显示出来,JTune 就是这样的一种工具(请参阅 参考资料)。观察 GC 之后堆大小的图,可以看到程序内存使用的趋势。对于大多数程序来说,可以将内存使用分为两部分:baseline 使用和current load 使用。对于服务器应用程序,baseline 使用就是应用程序在没有任何负荷、但是已经准备好接受请求时的内存使用,current load 使用是在处理请求过程中使用的、但是在请求处理完成后会释放的内存。只要负荷大体上是恒定的,应用程序通常会很快达到一个稳定的内存使用水平。如果在应用程序已经完成了其初始化并且负荷没有增加的情况下,内存使用持续增加,那么程序就可能在处理前面的请求时保留了生成的对象。
图 1 显示 GC 之后应用程序堆大小随着时间的变化图。上升趋势是存在内存泄漏的警示信号。(在真实的应用程序中,坡度不会这么大,但是在收集了足够长时间的 GC 数据后,上升趋势通常会表现得很明显。)
确信有了内存泄漏后,下一步就是找出哪种对象造成了这个问题。所有内存分析器都可以生成按照对象类进行分解的堆快照。有一些很好的商业堆分析工具,但是找出内存泄漏不一定要花钱买这些工具 —— 内置的 DE>hprofDE> 工具也可完成这项工作。要使用 DE>hprofDE> 并让它跟踪内存使用,需要以 DE>-Xrunhprof:heap=sitesDE> 选项调用 JVM。
清单 3 显示分解了应用程序内存使用的 DE>hprofDE> 输出的相关部分。(DE>hprofDE> 工具在应用程序退出时,或者用 DE>kill -3DE> 或在 Windows 中按 Ctrl+Break 时生成使用分解。)注意两次快照相比,DE>Map.EntryDE>、DE>TaskDE> 和 DE>int[]DE> 对象有了显著增加。
请参阅 清单 3。
清单 4 展示了 DE>hprofDE> 输出的另一部分,给出了 DE>Map.EntryDE> 对象的分配点的调用堆栈信息。这个输出告诉我们哪些调用链生成了 DE>Map.EntryDE> 对象,并带有一些程序分析,找出内存泄漏来源一般来说是相当容易的。
DE>
TRACE 300446:
java.util.HashMap$Entry.<init>(<Unknown Source>:Unknown line)
java.util.HashMap.addEntry(<Unknown Source>:Unknown line)
java.util.HashMap.put(<Unknown Source>:Unknown line)
java.util.Collections$SynchronizedMap.put(<Unknown Source>:Unknown line)
com.quiotix.dummy.MapLeaker.newTask(MapLeaker.java:48)
com.quiotix.dummy.MapLeaker.main(MapLeaker.java:64)
DE> |
另外
jstring jstr = (jstring)env->CallObjectMethod(authenRequest, mid_authenReq_getSdId_S);
env->GetStringUTFRegion(jstr,0,env->GetStringLength(jstr),authenReq.sd_id);
当jstr是null时,env->GetStringLength(jstr)会出错,导致jvm崩溃