理解GC日志
GC日志对于我们分析Java虚拟机内存问题很有帮助,GC日志格式有很多种,每一种格式都是由垃圾收集器来决定的,但是还是维持了一定的共性。下面就是一部分典型的GC日志(采用Parallel Scavenge和Parallel Old垃圾收集器)。
1 | {Heap before GC invocations=1 (full 0): |
可以看到这个日志呈现了一次Young GC过程。0.791代表了GC发生的时间,这个数字的含义是从Java虚拟机启动以来经过的秒数
。GC日志开头的 GC代表了GC的类型,这里是Young GC,如果是Full GC,那么这里就是Full GC。接下来的[PSYoungGen]
代表GC发生的区域,这里显示的内容跟采用不同的垃圾收集器有关,比如采用了ParNew
收集器,那么这里显示的就是ParNew
,我们这里采用的是Parallel Scavenge
收集器,所以显示的PSYoungGen
。后面的 65536K->6797K(76288K)
含义是 GC前该内存区域使用容量 -> GC后该内存区域使用容量(该内存区域总容量)
。65536K->6877K(251392K)
这个又代表了 GC前堆已使用容量 -> GC后堆使用容量(堆的总容量)
。再往后就是GC所花费的时间。比如说 [Times: user=0.01 sys=0.01, real=0.00 secs] ,分别代表用户态消耗的CPU时间
、内核态消耗的CPU时间
和操作从开始到结束所经过的CPU墙钟时间(Wall Clock Time)
。CPU时间和墙钟时间的区别是,墙钟时间包括各种非运算的等待耗时,例如等待磁盘I/O、线程阻塞,而CPU时间不包括这些耗时,但当系统有多CPU或者多核的话,多线程操作会叠加这些CPU时间,所以user或sys时间有时候会超过real时间。
PSYoung Gen total代表 新生代的容量,used 代表使用的容量,eden space 代表Eden空间容量,from space 代表From Survivor(S0)空间容量,to space代表To Survivor(S1)空间容量,后面的used代表该内存空间使用率。
ParOldGen total代表老年代的容量,used 代表使用的容量。
Metaspace 解释参考下图。
Metaspace由一个或多个虚拟空间组成,虚拟空间的分配单元是Chunk,其中Chunk使用列表进行维护。
当使用一个classLoader加载一个类时,过程如下:
1 | 1、当前classLoader是否有对应的Chunk且有足够的空间。 |
因为有GC的存在,有些Chunk的数据可能会被回收,那么这些Chunk属于committed的一部分,但不属于capacity。
另外,这些被分配的Chunk,基本很难被100%用完,存在碎片内存的情况,这些Chunk实际被使用的内存之和即used的大小;