JVM内存溢出与排错.docx_第1页
JVM内存溢出与排错.docx_第2页
JVM内存溢出与排错.docx_第3页
JVM内存溢出与排错.docx_第4页
JVM内存溢出与排错.docx_第5页
已阅读5页,还剩8页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

JVM内存溢出与排错一、JVM堆内存溢出Java堆用于存储对象实例,我们只要不断创建对象,并且保证GC Roots到对象之间有可达路径来避免垃圾回收机制来清除这些对象,就会在对象数量达到最大队的容量限制后产生内存溢出异常。代码:java view plaincopyprint?1. /* 2. * Java堆内存溢出 3. * author jiangtong 4. * 5. */ 6. public class HeapOOM 7. static class OOMObject 8.9. 10. /* 11. * -Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8 -XX:PermSize=32M -XX:MaxPermSize=64M -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError 12. */ 13. public static void main(String args) 14. List list = new ArrayList(); 15. int count = 0; 16. while(true) 17. try 18. count+; 19. list.add(new OOMObject(); 20. System.out.println(共构造了+count+个对象); 21. Thread.sleep(100); 22. catch (Exception e) 23. e.printStackTrace(); 24. 25. 26. 27. /* * Java堆内存溢出 * author jiangtong * */public class HeapOOM static class OOMObject/* * -Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8 -XX:PermSize=32M -XX:MaxPermSize=64M -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError */public static void main(String args) List list = new ArrayList(); int count = 0; while(true) try count+;list.add(new OOMObject();System.out.println(共构造了+count+个对象);Thread.sleep(100); catch (Exception e) e.printStackTrace(); 虚拟机执行参数说明:Xms20M -Xmx20M:最小堆内存和最大堆内存设置为一样是为了避免堆内存的自动扩展-Xmn10M:新生代内存分配10M,剩余的交给老年代-XX:SurvivorRatio=8:新生代中Eden区和Survivor区的内存比例为8:1-XX:PermSize=32M:永久代最小内存32M-XX:MaxPermSize=64M:永久代最大扩展内存64M-XX:+HeapDumpOnOutOfMemoryError:堆内存溢出时Dump出当前的内存堆转储快照以便事后分析1、控制台输出分析:GC DefNew: 8192K-1024K(9216K), 0.0426563 secs 8192K-4599K(19456K), 0.0427200 secs GC DefNew: 6237K-1024K(9216K), 0.0552875 secs 9813K-9742K(19456K), 0.0553528 secs GC DefNew: 7581K-7581K(9216K), 0.0000467 secsTenured: 8718K-10240K(10240K), 0.1228164 secs 16299K-11923K(19456K), Perm : 2086K-2086K(32768K), 0.1229961 secsFull GC Tenured: 10240K-7996K(10240K), 0.1247832 secs 19456K-15528K(19456K), Perm : 2086K-2086K(32768K), 0.1248966 secs Full GC Tenured: 8598K-8598K(10240K), 0.1296810 secs 17814K-17814K(19456K), Perm : 2086K-2086K(32768K), 0.1297631 secs Full GC Tenured: 8598K-8595K(10240K), 0.1481811 secs 17814K-17811K(19456K), Perm : 2086K-2084K(32768K), 0.1482582 secs java.lang.OutOfMemoryError: Java heap spaceDumping heap to java_pid3504.hprof .Heap dump file created 32580683 bytes in 1.553 secsException in thread main java.lang.OutOfMemoryError: Java heap spaceat java.util.Arrays.copyOf(Arrays.java:2760)at java.util.Arrays.copyOf(Arrays.java:2734)at java.util.ArrayList.ensureCapacity(ArrayList.java:167)at java.util.ArrayList.add(ArrayList.java:351)at biz.HeapOOM.main(HeapOOM.java:25)Heapdef new generation total 9216K, used 9216K 0x029e0000, 0x033e0000, 0x033e0000)eden space 8192K, 100% used 0x029e0000, 0x031e0000, 0x031e0000)from space 1024K, 100% used 0x031e0000, 0x032e0000, 0x032e0000)to space 1024K, 0% used 0x032e0000, 0x032e0000, 0x033e0000)tenured generation total 10240K, used 8601K 0x033e0000, 0x03de0000, 0x03de0000)the space 10240K, 84% used 0x033e0000, 0x03c46780, 0x03c46800, 0x03de0000)compacting perm gen total 32768K, used 2105K 0x03de0000, 0x05de0000, 0x07de0000)the space 32768K, 6% used 0x03de0000, 0x03fee770, 0x03fee800, 0x05de0000)No shared spaces configured.解读第一行代码:GC DefNew: 8192K-1024K(9216K), 0.0426563 secs 8192K-4599K(19456K), 0.0427200 secs其意思是对于本次Minor收集,新生代堆内存从占用8192K-收集后仅占用1024K,耗时0.0426563秒;而整个堆内存从占用内存8192K-收集后仅占用4599K,耗时0. 0427200秒观察整个输出去可以看出以供进行了三次MinorGC,三次FullGC,解释一下:l Minor GC新生代GC:指发生在新生代的垃圾收集动作,因为Java对象大多具有朝生夕灭的特性,所以Minor GC非常频繁,一般回收速度也较快l Full GC老年代GC、Major GC:指发生在老年代的GC,出现了Full GC,通常会伴随一次的Minor GC。FullGC一般比MinorGC慢10倍以上从上面的日志中我们总结如下:前提:我们创建的测试对象始终是没有释放内存的l 第一次的Minor GC和第一次Full GC成效比较显著相比较第二次手机回收的内存比较多,这是因为他们释放了本次运行程序之前生成的一些对象。l 从第二次Full GC效果就不那么显著了是因为,老年代的中已经没有多少可以释放的内存【我们创建的对象是一直不会释放的】。l 由于老年代内存的限制多次GC后无显著成效老年代已满,最终导致堆内存溢出,并生成了二进制格式的日志文件:java_pid3504.hprof,利用这个文件可以进行JVM内存溢出分析。l +HeapDumpOnOutOfMemoryError参数让我们看到了溢出后的堆内存情况,以下解读:n Heapn def new generation total 9216K, used 9216K 0x029e0000, 0x033e0000, 0x033e0000)/以上表示新生代总内存9216K,占用9216Kn eden space 8192K, 100% used 0x029e0000, 0x031e0000, 0x031e0000)/以上表示新生代的伊甸区总内存8192K,占用100%n from space 1024K, 100% used 0x031e0000, 0x032e0000, 0x032e0000)/以上表示from space幸存区总内存1024K,占用100%n to space 1024K, 0% used 0x032e0000, 0x032e0000, 0x033e0000)/以上表示to space幸存区总内存1024K,占用0%n tenured generation total 10240K, used 8601K 0x033e0000, 0x03de0000, 0x03de0000)n the space 10240K, 84% used 0x033e0000, 0x03c46780, 0x03c46800, 0x03de0000)/以上两行表示老年代总内存10240K,占用8601K,占用比例是84%n compacting perm gen total 32768K, used 2105K 0x03de0000, 0x05de0000, 0x07de0000)n the space 32768K, 6% used 0x03de0000, 0x03fee770, 0x03fee800, 0x05de0000)/以上两行表示永久代方法区总内存32768K,占用2105K,占用比例6%n No shared spaces configured.2、使用MAT对内存溢出日志“java_pid3504.hprof”进行分析2.1、安装MAT下载地址:/downloads/download.php?file=/mat/1.2.1/MemoryAnalyzer-01211051250.zip安装:我用的MyEclipse,将包解压到某个目录无限制,我放到这里:D:Program FilesGenuitecCommonMAT1.2配置一个插件的链接这个是必须的,路径:GenuitecMyEclipsedropins,在这个目录下建一个文件扩命名为.link,比如:MAT.link,这个文件内容就一句话:path=插件的解压路径,例如:path=D:/Program Files/Genuitec/Common/MAT1.22.2、获得堆转储文件你可以采用如下方式取得堆转储文件:l -XX:+HeapDumpOnOutOfMemoryErrorJVM 就会在发生内存泄露时抓拍下当时的内存状态,也就是我们想要的堆转储文件。这种方式适合于生产环境。本文采用的这种方式l -XX:+HeapDumpOnCtrlBreak如果你不想等到发生崩溃性的错误时才获得堆转储文件,也可以通过设置如下 JVM 参数来按需获取堆转储文件。除此之外,还有很多的工具,例如 JMap,JConsole 都可以帮助我们得到一个堆转储文件。您可以使用命令:JMap -dump:format=b,file= 不过,您需要了解到,不同厂家的 JVM 所生成的堆转储文件在数据存储格式以及数据存储内容上有很多区别, MAT 不是一个万能工具,它并不能处理所有类型的堆存储文件。但是比较主流的厂家和格式,例如 Sun, HP, SAP 所采用的 HPROF 二进制堆存储文件,以及 IBM 的 PHD 堆存储文件等都能被很好的解析。2.3、生成分析报告选择Eclipse的 File-Open,打开前面获得的堆转储文件,本文是:java_pid4456.hprof,打开这个文件后,如下图:同时我们注意到项目下面多了几个在打开过程中产生的分析文件:尤其是这个扩展名为.zip文件非常有意义,它是对分析结果做了一个压缩文件,压缩文件里面是网页格式的分析报告,这样你可以讲这个报告email给你的伙伴,你们一起分析。不得不说MAT想的周到J2.4、分析l 首先我们得到的是一个内存泄露推测的分析报告,这一点从标题上Leak Suspects可以看出来。点击LeaksOverview,我们看到如下:这个图上告诉我们总共堆内存17.6MB,灰色区域的对象占用了17.3MB,剩下的仅仅307.5KB,灰色区域就是推测存在内存泄露的区域,接下来的“Problem Suspect 1”里面为我们带来了这个区域的解释:上面的推测告诉我们:n 线程“main”持有了18,095,992字节大小的本地变量。n 内存被系统加载器System class loader加载的对象数组java.lang.Object的实例堆积.点击下面的”Details”:从上图中“Shortest Paths To the Accumulation Point”可以看出是“距离对象堆积点最近的路径”:main线程-ArrayList同时下面可以看到堆积的对象Accumulated Objects,我们可以看出这一样一个引用链:main线程引用Object,Object引用若干个OOMObject,每个OOMObject占用对内存8个字节对象头是8字节,成员变量int是4字节、String引用是4字节,我们这里的对象没有属性故是8字节。接下来是:从名字可以看出意思是:“通过XXX类堆积的对象”,从表格中我们不难看出:程序中biz.HeapOOM$OOMObject这个类的对象在堆内存上堆积了1,507,963个。使用了12,063,704个字节的对内存空间,很明显已经超出了我们定义的老年代的对内存上限-Xms20M -Xmx20M -Xmn10M,对内存共20M,新生代占用10M,剩下的是老年代的内存10M,由于这1,507,963个对象到GC root都有路径可达因此虚拟机无法释放他们占用的内存,导致内存泄露,进而导致内存溢出。二、JVM方法区内永久代存溢出1、 运行时常量池溢出在HotSpot虚拟机中运行时常量池是属于方法区的一部分,所以我们可以通过向运行时常量池中放入常量来导致方法区内存溢出。如果要向运行时常量池中添加内从,最简单的做法就是使用Sern()这个Native方法。该方法的作用是:如果池中已经包含一个等于此String对象的字符串,则返回代表池中这个字符串的String对象;否则将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。由于常量池分配在方法区内,我们可以通过-XX:PermSize和-XX:MaxPermSize限制方法区的大小。代码如下:java view plaincopyprint?1. /* 2. * 运行时常量池溢出 3. * -XX:PermSize=10M -XX:MaxPermSize=10M -XX:+HeapDumpOnOutOfMemoryError 4. * author jiangtong 5. * 6. */ 7. public class ConstanOOM 8.9. public static void main(String args) 10. List list = new ArrayList(); 11. int i=0; 12. while(true) 13. list.add(String.valueOf(i+).intern(); 14. System.out.println(i); 15. 16. 17. /* * 运行时常量池溢出 * -XX:PermSize=10M -XX:MaxPermSize=10M -XX:+HeapDumpOnOutOfMemoryError * author jiangtong * */public class ConstanOOM public static void main(String args) List list = new ArrayList();int i=0;while(true)list.add(String.valueOf(i+).intern();System.out.println(i);通过JVisualVM工具我们观察永久代内存的变化:永久代占用内存一直往上涨,由于MaxPermSize的限制是10导致内存溢出:java.lang.OutOfMemoryError: PermGen spaceDumping heap to java_pid9704.hprof .Heap dump file created 11755242 bytes in 0.594 secsException in thread main java.lang.OutOfMemoryError: PermGen spaceat java.lang.Sern(Native Method)at biz.ConstanOOM.main(ConstanOOM.java:19)通过Eclipse MAT分析:我们看得出堆积了大量的String对象。1、 方法区溢出方法区用于存放Class的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等。对这个区域的测试,基本思路是运行时产生大量的类去填充方法区,直到溢出。这里我们借助CGLib在运行时动态生成大量的动态类来达到目的。我们可以看看来自CGLib官方/的介绍:cglib is a powerful, high performance and quality Code Generation Library, It is used to extend JAVA classes and implements interfaces at runtime。示例代码:java view plaincopyprint?1. /* 2. * 方法区内存溢出 3. * -XX:PermSize=16M -XX:MaxPermSize=16M 4. * author jiangtong 5. * 6. */ 7. public class MethodAreaOOM 8.9. public static void main(String args) 10.11. while(true) 12. Enhancer enhancer = new Enhancer();

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论