工具在目录:C:\Java\jdk1.8.0_181\bin**
我们可以使用Java VisualVM浏览堆heap dump文件的内容,并查看堆中已分配的对象。 对我们需要进行heap dump分析的java程序点右键就能找到heap dump选项。一次heap dump是特定时间点Java虚拟机(JVM)堆中所有对象的一个快照。 JVM为所有类实例和数组对象在堆中分配内存。 当不再需要对象且没有对象的引用时,垃圾收集器将回收堆内存。 通过检查堆,可以找到创建对象的位置,并查找对这些对象的引用。 如果JVM无法从堆中删除不需要的对象,Java VisualVM可以帮助我们找到对象的最近的GC Root
可以发现占据最大堆内存的是一个byte类型的数组。另外有句题外话,在上图中我们发现String和char[]这两个类的数量几乎是相当的,这从侧面印证了String内部是由Char数组实现的。
本次GC日志是线上的Spark程序生成的。
spark 打印GC日志参数:
--conf "spark.executor.extraJavaOptions=
-verbose:gc -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC"
--conf "spark.driver.extraJavaOptions=
-verbose:gc -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC"
33.125:[GC[DefNew: 3324k->152k(3712k), 0.0025925 secs] 3324k>152k(11904k),0.0031680 secs]
从左至右,各个信息的意思为:
红色框:这个是参数 -XX:+PrintHeapAtGC的作用,可以直观的看到gc前后的堆内情况
//上图 蓝色部分
2022-07-26T18:59:58.040+0800: 23.716: [GC (Allocation Failure) [PSYoungGen: 527872K->24904K(613376K)] 561160K->58201K(2011648K), 0.0412419 secs] [Times: user=0.17 sys=0.02, real=0.04 secs]
Minor GC
。注意它不表示只GC新生代Allocation Failure:gc发生的原因,这里的Allocation Failure的原因是年轻代中没有足够区域能够存放需要分配的数据而失败
2022-07-26T18:59:44.478+0800: 26.155: [GC (Metadata GC Threshold) [PSYoungGen: 240047K->20620K(548864K)] 273344K->53925K(1947136K), 0.0370581 secs] [Times: user=0.29 sys=0.02, real=0.04 secs]
是一次minor gc
gc原因是:Metadata GC Threshold。Metadata即元数据的意思。我们可以看出这是与虚拟机的元数据区有关系的一次gc。元数据区,在jdk1.8以前又叫永久代,从JDK8开始,永久代(PermGen)的概念被废弃掉了,取而代之的就是这里的称为Metaspace的存储空间。元空间和永久代是虚拟机对方法区这个概念的一个具体实现。对于元空间而言,这一块空间是存在本地内存当中的。
以前只认为,Metaspace区是保存在本地内存中,是没有上限的,经查阅资料才发现,原来JDK8中,XX:MaxMetaspaceSize确实是没有上限的,最大容量与机器的内存有关;但是XX:MetaspaceSize是有一个默认值的:21M
一般情况下我们就设置一个XX:MetaspaceSize的JVM启动参数:-XX:MetaspaceSize=128M
这里元空间发生gc,说明元空间的内存不够了,到达了阀值。对元空间进行了一次垃圾回收,回收之前是240047K,回收之后是20620K
2022-07-26T18:59:44.391+0800: 10.068: [Full GC (Metadata GC Threshold) [PSYoungGen: 27258K->0K(613376K)] [ParOldGen: 18913K->33288K(1398272K)] 46172K->33288K(2011648K), [Metaspace: 55916K->55916K(1099776K)], 0.1719903 secs] [Times: user=2.97 sys=0.25, real=0.17 secs]
在元空间gc之后,紧接着发生了一次Full GC,且触发原因也是元空间不足。
[PSYoungGen: 27258K->0K(613376K)] :年轻代进行了一次gc
[ParOldGen: 18913K->33288K(1398272K)] :老年代进行了一次gc
[Metaspace: 55916K->55916K(1099776K)] : 元空间(方法区)发生了一次gc,但是值得注意的是,gc前后内存使用情况并没有发生任何改变。同时,元空间总的可使用的内存为:1gb。
{Heap before GC invocations=4275 (full 84):
PSYoungGen total 673792K, used 648704K [0x00000000d5580000, 0x0000000100000000, 0x0000000100000000)
eden space 648704K, 100% used [0x00000000d5580000,0x00000000fcf00000,0x00000000fcf00000)
from space 25088K, 0% used [0x00000000fcf00000,0x00000000fcf00000,0x00000000fe780000)
to space 25088K, 0% used [0x00000000fe780000,0x00000000fe780000,0x0000000100000000)
ParOldGen total 1398272K, used 1397936K [0x0000000080000000, 0x00000000d5580000, 0x00000000d5580000)
object space 1398272K, 99% used [0x0000000080000000,0x00000000d552c020,0x00000000d5580000)
Metaspace used 133520K, capacity 143098K, committed 143508K, reserved 1175552K
class space used 16519K, capacity 17415K, committed 17596K, reserved 1048576K
2022-07-27T00:06:39.271+0800: 18424.947: [Full GC (Ergonomics) [PSYoungGen: 648704K->38610K(673792K)] [ParOldGen: 1397936K->1397899K(1398272K)] 2046640K->1436509K(2072064K), [Metaspace: 133520K->133520K(1175552K)], 0.7624691 secs] [Times: user=17.74 sys=0.01, real=0.76 secs]
Heap after GC invocations=4275 (full 84):
PSYoungGen total 673792K, used 38610K [0x00000000d5580000, 0x0000000100000000, 0x0000000100000000)
eden space 648704K, 5% used [0x00000000d5580000,0x00000000d7b34870,0x00000000fcf00000)
from space 25088K, 0% used [0x00000000fcf00000,0x00000000fcf00000,0x00000000fe780000)
to space 25088K, 0% used [0x00000000fe780000,0x00000000fe780000,0x0000000100000000)
ParOldGen total 1398272K, used 1397899K [0x0000000080000000, 0x00000000d5580000, 0x00000000d5580000)
object space 1398272K, 99% used [0x0000000080000000,0x00000000d5522c38,0x00000000d5580000)
Metaspace used 133520K, capacity 143098K, committed 143508K, reserved 1175552K
class space used 16519K, capacity 17415K, committed 17596K, reserved 1048576K
}
以上是gc日志的分析,下几篇会讲解一下常见的full gc情况的排查和解决过程