JAVA内存泄漏及诊断

2,044 views

Published on

有关Java内存泄漏的一个例子

Published in: Technology, News & Politics
  • Be the first to comment

JAVA内存泄漏及诊断

  1. 1. JAVA 内存泄漏及其诊断@ivannotes2012-05-04
  2. 2. Agenda• 什么是内存泄漏• 一个真实的例子• 诊断泄漏点• 利用工具发现泄漏• 参考资料• Q&A
  3. 3. 什么是内存泄漏• JAVA 存在内存泄漏C 的例子:int *pi; void foo() { pi = (int*) malloc(8*sizeof(int)); // oops, memory leak of 4 ints // use pi free(pi); // foo() is done with pi }void main() { pi = (int*) malloc(4*sizeof(int)); foo(); pi[0] = 10; // oops, pi is now a dangling pointer}
  4. 4. Java 的例子import java.io.IOException;import java.util.HashSet;import java.util.Random;import java.util.Vector;public class LeakExample { static Vector myVector = new Vector(); static HashSet pendingRequests = new HashSet(); public void slowlyLeakingVector(int iter, int count) { for (int i=0; i<iter; i++) { for (int n=0; n<count; n++) { myVector.add(Integer.toString(n+i)); } for (int n=count-1; n>0; n--) { // Oops, it should be n>=0 myVector.removeElementAt(n); } } }
  5. 5. Java 的例子public void leakingRequestLog(int iter) { Random requestQueue = new Random(); for (int i=0; i<iter; i++) { int newRequest = requestQueue.nextInt(); pendingRequests.add(new Integer(newRequest)); // processed request, but forgot to remove it // from pending requests } } public void noLeak(int size) { HashSet tmpStore = new HashSet(); for (int i=0; i<size; ++i) { String leakingUnit = new String("Object: " + i); tmpStore.add(leakingUnit); } // Though highest memory allocation happens in this // function, but all these objects get garbage // collected at the end of this method, so no leak. }
  6. 6. Java 的例子 public static void main(String[] args) throws IOException { LeakExample javaLeaks = new LeakExample(); for (int i=0; true; i++) { try { // sleep to slow down leaking process Thread.sleep(1000); } catch (InterruptedException e) { /* do nothing */ } System.out.println("Iteration: " + i); javaLeaks.slowlyLeakingVector(1000,10); javaLeaks.leakingRequestLog(5000); javaLeaks.noLeak(100000); } }}
  7. 7. 什么是内存泄漏对于 JAVA 来说一个对象被程序使用过后在程序接下来的生命周期内都不会再使用,那它就是内存泄漏。因为它已经不会再被用到,但却占用了内存并且不能被回收。
  8. 8. 一个真实的例子背景: 该死的 JVM GC 报警短信
  9. 9. 诊断泄漏点• 问题代码String name = request.getServletPath();ProfilerPoint profiler = profilerManager.getProfilerPoint(name,domain);public ProfilerPoint getProfilerPoint(String name,String domain){ ProfilerPoint point = points.get(name); if(point==null){ point = new ProfilerPoint(name,domain); ProfilerPoint old = points.putIfAbsent(name, point); if(old!=null)return old; } return point;} 永远只会变大的 points 。因为我们采用了 REST 风格的 URL 所以随着内容的增 多 URL 的数量会越来越多,这里的统计不应该根据 URL 去统计,个应该根据正 则的 URL 映射表去统计
  10. 10. 利用工具发现泄漏• 这次的问题中我们用到的工具jmapjstatgc.logjvisualvmOther Tools can be usedGCLogViewerIBM Monitoring and Diagnostic Tools for Java
  11. 11. 利用工具发现泄漏• gc log 开启 GC log 的方法。在 JVM 中添加如下参数 -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:somefile.log• Jstat jstat –gc pid jstat –gcutil pid 1000 10 其中 pid 是 jvm 进程号, jstat –gcutil 1000 是代表每隔 1 秒执行一次, 10 代表一共执行 10 次
  12. 12. 利用工具发现泄漏• Jmap jmap –histo:live pid 执行该命令可以打印出当前堆中活着的对象,我们来看看出问题的时候这里 是什么样子的
  13. 13. 利用工具发现泄漏• Jvisualvm
  14. 14. 参考资料• http://www.ibm.com/developerworks/rational/library• http:// www.ibm.com/developerworks/java/jdk/tools/gcmv /• http://www.ibm.com/developerworks/java/jdk/tools/
  15. 15. Q&A

×