日度归档:2013年5月14日

jni内存泄露

在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 数据后,上升趋势通常会表现得很明显。)
图 1. 持续上升的内存使用趋势

确信有了内存泄漏后,下一步就是找出哪种对象造成了这个问题。所有内存分析器都可以生成按照对象类进行分解的堆快照。有一些很好的商业堆分析工具,但是找出内存泄漏不一定要花钱买这些工具 —— 内置的 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> 对象,并带有一些程序分析,找出内存泄漏来源一般来说是相当容易的。
清单 4. HPROF 输出,显示 Map.Entry 对象的分配点

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崩溃

FROM: http://www.blogjava.net/neumqp/archive/2006/03/02/33152.html