设为首页 加入收藏

TOP

排查Java的内存问题(一)
2018-03-18 16:21:24 】 浏览:1070
Tags:排查 Java 内存 问题

对于一个Java进程来说,会有多个内存池或空间——Java堆、Metaspace、PermGen(在Java 8之前的版本中)以及原生堆。


每个内存池都可能会遇到自己的内存问题,比如不正常的内存增加、应用变慢或者内存泄露,每种形式的问题最终都会以各自空间OutOfMemoryError的形式体现出来。


在本文中,我们会尝试理解这些OutOfMemoryError错误信息的含义以及分析和解决这些问题要收集哪些诊断数据,另外还会研究一些用来收集和分析数据的工具,它们有助于解决这些内存问题。本文的关注点在于如何处理这些内存问题以及如何在生产环境中避免出现这些问题。


Java HotSpot VM所报告的OutOfMemoryError信息能够清楚地表明哪块内存区域正在耗尽。接下来,让我们仔细看一下各种OutOfMemoryError信息,理解其含义并探索导致它们出现的原因,最后介绍如何排查和解决这些问题。


Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOfRange(Unknown Source)
at java.lang.String.<init>(Unknown Source)
at java.io.BufferedReader.readLine(Unknown Source)
at java.io.BufferedReader.readLine(Unknown Source)
at com.abc.ABCParser.dump(ABCParser.java:23)
at com.abc.ABCParser.mainABCParser.java:59)


这个信息表示JVM在Java堆上已经没有空闲的空间,JVM无法继续执行程序了。这种错误最常见的原因就是指定的最大Java堆空间已经不足以容纳所有的存活对象了。要检查Java堆空间是否足以容纳JVM中所有存活的对象,一种简单的方式就是检查GC日志。


688995.775: [Full GC [PSYoungGen: 46400K->0K(471552K)] [ParOldGen: 1002121K->304673K(1036288K)] 1048
521K->304673K(1507840K) [PSPermGen: 253230K->253230K(1048576K)], 0.3402350 secs] [Times: user=1.48
sys=0.00, real=0.34 secs]


从上面的日志条目我们可以看到在Full GC之后,堆的占用从1GB(1048521K)降低到了305MB(304673K),这意味着分配给堆的1.5GB(1507840K)足以容纳存活的数据集。


现在,我们看一下如下的GC活动:


 20.343: [Full GC (Ergonomics) [PSYoungGen: 12799K->12799K(14848K)] [ParOldGen: 33905K->33905K(34304K)] 46705K- >46705K(49152K), [Metaspace: 2921K->2921K(1056768K)], 0.4595734 secs] [Times: user=1.17 sys=0.00, real=0.46 secs]
...... <snip> several Full GCs </snip> ......
22.640: [Full GC (Ergonomics) [PSYoungGen: 12799K->12799K(14848K)] [ParOldGen: 33911K->33911K(34304K)] 46711K- >46711K(49152K), [Metaspace: 2921K->2921K(1056768K)], 0.4648764 secs] [Times: user=1.11 sys=0.00, real=0.46 secs]
23.108: [Full GC (Ergonomics) [PSYoungGen: 12799K->12799K(14848K)] [ParOldGen: 33913K->33913K(34304K)] 46713K- >46713K(49152K), [Metaspace: 2921K->2921 K(1056768K)], 0.4380009 secs] [Times: user=1.05 sys=0.00, real=0.44 secs]
23.550: [Full GC (Ergonomics) [PSYoungGen: 12799K->12799K(14848K)] [ParOldGen: 33914K->33914K(34304K)] 46714K- >46714K(49152K), [Metaspace: 2921K->2921 K(1056768K)], 0.4767477 secs] [Times: user=1.15 sys=0.00, real=0.48 secs]
24.029: [Full GC (Ergonomics) [PSYoungGen: 12799K->12799K(14848K)] [ParOldGen: 33915K->33915K(34304K)] 46715K- >46715K(49152K), [Metaspace: 2921K->2921 K(1056768K)], 0.4191135 secs] [Times: user=1.12 sys=0.00, real=0.42 secs] Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded at oom.main(oom.java:15)


从转储的“Full GC”频率信息我们可以看到,这里存在多次连续的Full GC,它会试图回收Java堆中的空间,但是堆已经完全满了,GC并没有释放任何空间。这种频率的Full GC会对应用的性能带来负面的影响,会让应用变慢。这个样例表明应用所需的堆超出了指定的Java堆的大小。增加堆的大小会有助于避免full GC并且能够规避OutOfMemoryError。Java堆的大小可以通过-Xmx JVM选项来指定:


java –Xmx1024m –Xms1024m Test


OutOfMemoryError可能也是应用存在内存泄露的一个标志。内存泄露通常难以察觉,尤其是缓慢的内存泄露。如果应用无意间持有了堆中对象的引用,会造成内存的泄露,这会导致对象无法被垃圾回收。随着时间的推移,在堆中这些无意被持有的对象可能会随之增加,最终填满整个Java堆空间,导致频繁的垃圾收集,最终程序会因为OutOfMemoryError错误而终止。


请注意,最好始终启用GC日志,即便在生产环境也如此,在出现内存问题时,这样有助于探测和排查。如下的选项能够用来开启GC日志:


-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintGCDateStamps
-Xloggc:<gc l

首页 上一页 1 2 3 4 5 6 7 下一页 尾页 1/9/9
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇从 HelloWorld 看 Java 字节码文.. 下一篇Android基础知识:Activity中获取..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目