JVM(6)——GC日志与实例分析

这里会记录 《深入理解java虚拟机》的所有知识点哟~

预备知识

JVM中的老年代与新生代

JVM中分为老年代和新生代。一般情况下,新创建的对象都会被分配到Eden区(一些大对象特殊处理),这些对象经过第一次Minor GC后,如果仍然存活,将会移到Survivor区。对象在Survivor区中每熬过一次Minor GC,年龄就会增加1岁,当它的年龄增加到一定程度时,就会被移动到老年代中。

Survivor区分为两个“From”和“To”
在GC开始的时候,对象只会存在于Eden区和名为“From”的Survivor区,Survivor区“To”是空的。紧接着进行GC,Eden区中所有存活的对象都会被复制到“To”,而在“From”区中,仍然存活的对象会根据他们的年龄值来决定去向。年龄达到一定值(年龄阈值,可以通过:XX:Max Tenuring Threshold来设置)的对象会被移动到老年代中,没有达到阈值的对象会被复制到“To”区域。经过这次GC后,Eden区和From区已经被清空。这个时候,“From”和“To”会交换他们的角色,也就是新的“To”就是上次GC前的“From”,新的“From”就是上次GC前的“To”。不论如何,都会保证名为“To”的Survivor区域是空的。Minor GC会一直重复这样的过程,直到“To”区被填满,“To”区被填满之后,会将所有对象移动到老年代中。

这里写图片描述
如上图:堆被划分成2个不同区域:新生代、老年代。新生代又被划分为三个区域:Eden、From Survivor、To Survivor

Minor GC和Full GC

Minor GC:发生在新生代的垃圾收集动作,该动作非常频繁。采用复制算法
Full GC:发生在老年代的垃圾收集动作,出现了Major GC,经常会伴随至少一次Minor GC。Major GC的速度一般会比Minor GC慢10倍以上

GC日志

设置JVM参数为 - XX: + PrintGCDetails,控制台就可以显示GC日志的相关信息,下面给出GC日志中的各个参数代表的含义

这里写图片描述

这里写图片描述

“GC”与“Full GC”:
GC日志开头的“GC”与“Full GC”说明了这次垃圾收集的停顿类型,如果有“Full”就说明这次GC是发生了Stop- The- World的。

“PSYoungGen:”

  • 如果使用的是Serial收集器中的新生代名为“Default New Generation”,所以显示的是“[DefNew”;
  • 如果使用的是ParNew收集器,新生代名称会变为“[ParNew”,意为“Parallel New Generation”;
  • 如果采用Parallel Scavenge收集器,新生代名称变为“PSYoungGen” ,老年代和永久带同理,名称也是由收集器决定的。

从Full GC信息可知,新生代可用的内存大小约为18M,则新生代分配得到的内存空间约为20M。老年代分得的内存大小约为42M,堆的可用内存的大小约为60M。可以计算出:18432K(新生代可用空间) + 42112K(老年代空间) = 60544K(堆的可用空间)。新生代约占堆的大小1/3,老年代约占堆的大小2/3。可以看出,GC对新生代的回收比较乐观,而堆老年代以及方法区的回收并不明显。

JVM参数

配置参数功 能
-Xms初始堆大小
-Xmx最大堆大小
-Xmn新生代大小。通常为Xmx的1/3或者1/4。新生代 = Eden + 2个Survivor空间。实际可用空间为 Eden + 1个Survivor
-Xss每个线程堆栈大小为1M,一般来说如果栈不是很深的话,1M是够用的
-XX: NewRatio新生代与老年代的比例,如:-XX:NewRatio = 2,说明新生代占整个堆空间的1/3,老年代占2/3
-XX: SurvivorRatio新生代中Eden与Survivor的比值。默认值为8
-XX: MaxPermSize永久代(方法区)的最大值
-XX: PrintGCDetails打印GC信息
-XX: +HeapDumpOutOfMemoryError让虚拟机在发生内存溢出时Dump出当前的内存堆转出快照,以便分析用

实例分析

/** 
  -Xms60m  初始堆大小60
  -Xmx60m  最大堆大小60
  -Xmn20m  新生代大小20
  -XX:NewRatio=2 ( 若 Xms = Xmx, 并且设定了 Xmn, 那么该项配置就不需要配置了 ) 
  -XX:SurvivorRatio=8  新生代中Eden与Survivor的比值
  -XX:PermSize=30m  永久代(方法区)的初始大小
  -XX:MaxPermSize=30m  永久代的最大值
  -XX:+PrintGCDetails 打印GC信息
  */
public class TestAllocation {
    public static void doTest() {
        Integer M = new Integer(1024 * 1024 * 1); 
        byte[] bytes = new byte[1 * M]; //申请1M大小的内存空间
        bytes = null; //断开引用链
        System.gc(); //通知GC收集垃圾
        System.out.println();
        bytes = new byte[1 * M]; //重新申请1M大小的内存空间
        bytes = new byte[1 * M]; //再次申请1M大小的空间
        System.gc();
        System.out.println();
    }
    public static void main(String[] agrs){
        TestAllocation.doTest();
    }
}

运行结果

[GC (System.gc()) [PSYoungGen: 2343K->720K(18432K)] 2343K->728K(59392K), 0.0011120 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (System.gc()) [PSYoungGen: 720K->0K(18432K)] [ParOldGen: 8K->555K(40960K)] 728K->555K(59392K), [Metaspace: 2736K->2736K(1056768K)], 0.0053624 secs] [Times: user=0.05 sys=0.00, real=0.01 secs] 

[GC (System.gc()) [PSYoungGen: 2375K->1056K(18432K)] 2930K->1611K(59392K), 0.0005826 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (System.gc()) [PSYoungGen: 1056K->0K(18432K)] [ParOldGen: 555K->1578K(40960K)] 1611K->1578K(59392K), [Metaspace: 2737K->2737K(1056768K)], 0.0039382 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 

Heap
 PSYoungGen      total 18432K, used 328K [0x00000000fec00000, 0x0000000100000000, 0x0000000100000000)
  eden space 16384K, 2% used [0x00000000fec00000,0x00000000fec52060,0x00000000ffc00000)
  from space 2048K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x0000000100000000)
  to   space 2048K, 0% used [0x00000000ffc00000,0x00000000ffc00000,0x00000000ffe00000)
 ParOldGen       total 40960K, used 1578K [0x00000000fc400000, 0x00000000fec00000, 0x00000000fec00000)
  object space 40960K, 3% used [0x00000000fc400000,0x00000000fc58a998,0x00000000fec00000)
 Metaspace       used 2744K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 295K, capacity 386K, committed 512K, reserved 1048576K
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=30m; support was removed in 8.0
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=30m; support was removed in 8.0

这里所配置的Xmn为20M,也就是指定了新生代的内存空间为20M,课时从打印的堆信息来看,新生代只有18M。另外的2M哪里去了呢?是这样的。新生代 = eden + from + to = 16 + 2 + 2 = 20M,可见新生代的内存空间确实是按照Xmn参数分配得到的。而且这里制定了SurvivorRatio = 8, 因此,eden = 8/10的新生代空间 = 8 / 10 * 20M = 16M。from = to = 1 / 10 * 20M = 2M。堆信息中新生代的total18432K是这样来的:eden + from survivor = 16384K + 2048K = 18432K, 约为18M。因此可以知道,这里新生代的内存空间指的是新生代可用的总的内存空间 ,而不是整个新生代的空间大小。另外,可以看出老年代的内存空间为40960K,约为40M。堆大小 = 新生代 + 老年代。因此,老年代 = 堆大小 - 新生代 = 60 - 20 = 40M。

看上述示例:
第16行触发的Minor GC收集分析:

这里写图片描述
从上图可以看出,在第14行为bytes分配的内存空间已经被回收完成。引起GC回收这1M内存空间的因素是第15行的bytes = null,bytes为null表明之前申请的那1M的内存空间现在已经没有任何引用变量使用它,因此它在内存中处于一种不可达状态。那么,当Minor GC发生的时候,GC会来回收这部分内存空间。

第16行触发的Full GC收集分析:

这里写图片描述
从上图可以看出,在Full GC后,新生代的内存使用变为0K,那么这720K内存到哪里去了?难道都被GC当成垃圾回收掉了?当然不是

这里写图片描述

可以看到,Full GC后,老年代的内存从8K变为555K。当Full GC进行的时候,默认的方式是尽量清空新生代,因此在调用System.get()时,新生代中存活的对象会提前进入老年代。

第20行触发的Minor GC收集分析:
这里写图片描述

在第18行创建的大小为1M的数组被GC回收了。在第19行创建的,大小也为1M的数组由于bytes引用变量还在引用它,因此,它暂时未被GC回收

第20行触发的Full GC收集分析:
这里写图片描述

如上图所示,可以知道,新生代中存活的对象又提前进入老年代了。

参考

https://blog.csdn.net/gyqjn/article/details/49848473
这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值