GC日志分析

JVM内存

heap结构

按分代,分young-eden,young-survivor,old
用-Xmn,-Xms,-Xmx来指定

non-heap结构
包括metaspace,thread stacks,compiled native code,memory allocated by native code
-XX:PermSize或-XX:MetaspceSize,-Xss或-XX:ThreadStackSize


查看日志

JVM的GC日志的主要参数包括如下几个:

  • -XX:+PrintGC 输出GC日志

  • -XX:+PrintGCDetails 输出GC的详细日志

  • -XX:+PrintGCTimeStamps 输出GC的时间戳(以基准时间的形式)

  • -XX:+PrintGCDateStamps 输出GC的时间戳(以日期的形式,如 2013-05-04T21:53:59.234+0800)

  • -XX:+PrintHeapAtGC 在进行GC的前后打印出堆的信息

  • -Xloggc:../logs/gc.log 日志文件的输出路径


实验

在Eclipse中设置运行配置:-XX:+PrintGCDetails
1.无内存分配
代码:

 System.gc();
//什么也不做

结果如下:
[GC (System.gc())
[PSYoungGen: 1485K->712K(16896K)] 1485K->720K(55296K), 0.0029656 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (System.gc())
[PSYoungGen: 712K->0K(16896K)] [ParOldGen: 8K->627K(38400K)] 720K->627K(55296K), [Metaspace: 2783K->2783K(1056768K)], 0.0138246 secs] [Times: user=0.06 sys=0.00, real=0.01 secs]
Heap
PSYoungGen total 16896K, used 148K [0x00000000edb80000, 0x00000000eee00000, 0x0000000100000000)
eden space 14848K, 1% used [0x00000000edb80000,0x00000000edba5360,0x00000000eea00000)
from space 2048K, 0% used [0x00000000eea00000,0x00000000eea00000,0x00000000eec00000)
to space 2048K, 0% used [0x00000000eec00000,0x00000000eec00000,0x00000000eee00000)
ParOldGen total 38400K, used 627K [0x00000000c9200000, 0x00000000cb780000, 0x00000000edb80000)
object space 38400K, 1% used [0x00000000c9200000,0x00000000c929cd30,0x00000000cb780000)
Metaspace used 2790K, capacity 4486K, committed 4864K, reserved 1056768K
class space used 298K, capacity 386K, committed 512K, reserved 1048576K

分析:

  • PSYoungGen:新生代收集器,使用复制算法,并行的多线程的收集器
    初始新生代大小1485K

  • ParOldGen: Parallel Scavenge收集器的老年代版本,使用多线程和标记整理算法

  • Metaspace: java8的时候去除PermGen,将其中的方法区移到non-heap中的Metaspace
    Metaspace与PermGen之间最大的区别在于:Metaspace并不在虚拟机中,而是使用本地内存

三个数字表示地址,在HotSpot里分别称为
low_boundary:reserved space的最低地址边界,通常跟“low”相等
high:commited space的最高地址边界
high_boundary:reserved space最高地址边界

reserved space的大小就是max capacity–[low_boundary, high_boundary)
commited space的大小就是current capacity–[low, high)

2.不回收
代码:

int size = 1024 * 1024;
byte[] data = new byte[size];

结果如下:
Heap
PSYoungGen total 16896K, used 2806K
[0x00000000edb80000, 0x00000000eee00000, 0x0000000100000000)

  • eden space 14848K, 18% used
    [0x00000000edb80000,0x00000000ede3da68,0x00000000eea00000)
  • from space 2048K, 0% used
    [0x00000000eec00000,0x00000000eec00000,0x00000000eee00000)
  • to space 2048K, 0% used
    [0x00000000eea00000,0x00000000eea00000,0x00000000eec00000)

ParOldGen total 38400K, used 0K [0x00000000c9200000, 0x00000000cb780000, 0x00000000edb80000)

  • object space 38400K, 0% used
    [0x00000000c9200000,0x00000000c9200000,0x00000000cb780000)

Metaspace used 2790K, capacity 4486K, committed 4864K, reserved 1056768K

  • class space used 298K, capacity 386K, committed 512K, reserved
    1048576K

分析:
分配了1024*1024内存,即1024K,仅以下发生改变
分配之前:
PSYoungGen total 16896K, used 1782K
eden space 14848K, 12% used
分配之后:
PSYoungGen total 16896K, used 2806K
eden space 14848K, 18% used

新生代eden space增加了1024K

3.回收

直接调用System.gc,触发Full GC执行。

int size = 1024 * 1024;
byte[] data = new byte[size];
// 将data置为null即让它成为垃圾
data = null;
// 通知垃圾回收器回收垃圾
System.gc();

结果如下:
[GC (System.gc())
[PSYoungGen: 2509K->712K(16896K)] 2509K->720K(55296K), 0.0028822 secs]
[Times: user=0.00 sys=0.00, real=0.00 secs]

[Full GC (System.gc()) [PSYoungGen: 712K->0K(16896K)] [ParOldGen: 8K->627K(38400K)] 720K->627K(55296K), [Metaspace: 2783K->2783K(1056768K)], 0.0153738 secs]
[Times: user=0.05 sys=0.01, real=0.02 secs]

Heap
PSYoungGen total 16896K, used 148K [0x00000000edb80000, 0x00000000eee00000, 0x0000000100000000)
eden space 14848K, 1% used [0x00000000edb80000,0x00000000edba5360,0x00000000eea00000)
from space 2048K, 0% used [0x00000000eea00000,0x00000000eea00000,0x00000000eec00000)
to space 2048K, 0% used [0x00000000eec00000,0x00000000eec00000,0x00000000eee00000)
ParOldGen total 38400K, used 627K [0x00000000c9200000, 0x00000000cb780000, 0x00000000edb80000)
object space 38400K, 1% used [0x00000000c9200000,0x00000000c929cc50,0x00000000cb780000)
Metaspace used 2790K, capacity 4486K, committed 4864K, reserved 1056768K


分析
[GC (System.gc())
[PSYoungGen: 2509K->712K(16896K)]
2509K->720K(55296K), 0.0028822 secs]
[Times: user=0.00 sys=0.00, real=0.00 secs]

  • 使用PSYoungGen作为年轻代的垃圾收集器
  • 回收前年轻代大小2509K
  • 回收后年轻代大小712K
  • 年轻代总大小16896K
  • 回收前堆区的大小2509K
  • 回收后堆区的大小720K
  • 堆区总大小55296K
  • 回收时间0.0028822 secs
  • 用户耗时
  • 系统耗时
  • 实际耗时
  • -

[Full GC (System.gc())
[PSYoungGen: 712K->0K(16896K)]
[ParOldGen: 8K->627K(38400K)] 720K->627K(55296K),
[Metaspace: 2783K->2783K(1056768K)], 0.0153738 secs]
[Times: user=0.05 sys=0.01, real=0.02 secs]

gc回收后:
PSYoungGen新生代大小从2509K减少至712K
Full GC回收后:
PSYoungGen新生代大小从712K减少至0K
ParOldGen年老代大小从8K增加至627K
堆区大小从720减少至627K

验证:
初始新生代大小1485K,分配1024K即2509K
gc回收前新生代2509K 年老代0K 堆区大小2509K
gc回收后新生代712K 年老代8K 堆区大小720K
Full gc后新生代0K 年老代627K 堆区大小627K
最终堆区信息如下:
PSYoungGen total 16896K, used 148K
ParOldGen total 38400K, used 627K

解释:

  • 初始对象都分配在新生代
  • gc只针对新生代回收,几次GC以后将持久对象转移至年老代
  • Full gc对所有堆进行回收,把old,young里面大部分垃圾回收掉
  • 堆信息中新生代的 total 16896K是这样来的
    eden + 1 个 survivor = 14848K+ 2048K = 16896K
    因为 jvm 每次只是用新生代中的 eden 和 一个 survivor,因此新生代实际的可用内存空间大小为所指定的 90%。

因此可以知道,这里新生代的内存空间指的是新生代可用的总的内存空间,而不是指整个新生代的空间大小。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值