java gcroot标记时机_详解GC机制及Minor GC和Full GC触发条件总结

概述今天主要分享下GC相关概念,为啥要讲GC呢?因为作为运维,很多时候系统都会报错内存溢位之类,而这时候都不知道源头在哪?学习一下GC的机制及Minor GC和Full GC触发条件还是有用的。

GC机制GC,即就是Java垃圾回收机制。目前主流的JVM(HotSpot)采用的是分代收集算法。与C++不同的是,Java采用的是类似于树形结构的可达性分析法来判断物件是否还存在引用。即:从gcroot开始,把所有可以搜寻得到的物件标记为存活物件。

要准确理解Java的垃圾回收机制,就要从:“什么时候”,“对什么东西”,“做了什么”三个方面来具体分析。

第一:“什么时候”即就是GC触发的条件。GC触发的条件有两种。(1)程式呼叫System.gc时可以触发;(2)系统自身来决定GC触发的时机。

系统判断GC触发的依据:根据Eden区和From Space区的内存大小来决定。当内存大小不足时,则会启动GC执行绪并停止应用执行绪。

第二:“对什么东西”笼统的认为是Java物件并没有错。但是准确来讲,GC操作的物件分为:通过可达性分析法无法搜寻到的物件和可以搜寻到的物件。对于搜寻不到的方法进行标记。

第三:“做了什么”最浅显的理解为释放物件。但是从GC的底层机制可以看出,对于可以搜寻到的物件进行复制操作,对于搜寻不到的物件,呼叫finalize()方法进行释放。

具体过程:当GC执行绪启动时,会通过可达性分析法把Eden区和From Space区的存活物件复制到To Space区,然后把Eden Space和From Space区的物件释放掉。当GC轮训扫描To Space区一定次数后,把依然存活的物件复制到老年代,然后释放To Space区的物件。

17f13a15105f78e45b3739c1b6e32731.jpg

对于用可达性分析法搜寻不到的物件,GC并不一定会回收该物件。要完全回收一个物件,至少需要经过两次标记的过程。

第一次标记:对于一个没有其他引用的物件,筛选该物件是否有必要执行finalize()方法,如果没有执行必要,则意味可直接回收。(筛选依据:是否复写或执行过finalize()方法;因为finalize方法只能被执行一次)。

第二次标记:如果被筛选判定位有必要执行,则会放入FQueue伫列,并自动建立一个低优先级的finalize执行绪来执行释放操作。如果在一个物件释放前被其他物件引用,则该物件会被移除FQueue伫列。

GC过程中用到的回收算法:

通过上面的GC过程不难看出,Java堆中的年轻代和老年代采用了不同的回收算法。年轻代采用了复制法;而老年代采用了标记-整理法

7305ef581fed64e9de61d15a59776a03.jpg

程式计数器:执行绪私有。是一块较小的内存,是当前执行绪所执行的字节码的行号指示器。是Java虚拟机器规范中唯一没有规定OOM(OutOfMemoryError)的区域。

Java栈:执行绪私有。生命周期和执行绪相同。是Java方法执行的内存模型。执行每个方法都会建立一个栈帧,用于储存区域性变数和算子(物件引用)。区域性变数所需要的内存空间大小在编译期间完成分配。所以栈帧的大小不会改变。存在两种异常情况:若执行绪请求深度大于栈的深度,抛StackOverflowError。若栈在动态扩充套件时无法请求足够内存,抛OOM。

Java堆:所有执行绪共享。虚拟机器启动时建立。存放物件例项和阵列。所占内存最大。分为新生代(Young区),老年代(Old区)。新生代分Eden区,Servior区。Servior区又分为From space区和To Space区。Eden区和Servior区的内存比为8:1。 当扩充套件内存大于可用内存,抛OOM。

方法区:所有执行绪共享。用于储存已被虚拟机器载入的类资讯、常量、静态变数等资料。又称为非堆(Non – Heap)。方法区又称“永久代”。GC很少在这个区域进行,但不代表不会回收。这个区域回收目标主要是针对常量池的回收和对型别的解除安装。当内存申请大于实际可用内存,抛OOM。

本地方法栈:执行绪私有。与Java栈类似,但是不是为Java方法(字节码)服务,而是为本地非Java方法服务。也会抛StackOverflowError和OOM。

Minor GC和Full GC概念:新生代GC(Minor GC):指发生在新生代的垃圾收集动作,因为Java物件大多都具备朝生夕灭的特性,所以Minor GC非常频繁,一般回收速度也比较快。

9dcdb0c8d3c93c716036b72e8149dc82.jpg

老年代GC(Major GC/Full GC):指发生在老年代的GC,出现了Major GC,经常会伴随至少一次的Minor GCMajor GC的速度一般会比Minor GC慢10倍以上。

Minor GC ,Full GC 触发条件Minor GC触发条件:当Eden区满时,触发Minor GC。

Full GC触发条件:

(1)呼叫System.gc时,系统建议执行Full GC,但是不必然执行

(2)老年代空间不足

(3)方法区空间不足

(4)通过Minor GC后进入老年代的平均大小大于老年代的可用内存

(5)由Eden区、From Space区向To Space区复制时,物件大小大于To Space可用内存,则把该物件转存到老年代,且老年代的可用内存小于该物件大小

新生代可用的GC?新生代中物件存活的时间比较短,因此给予Copying算法实现,Eden区域存放新建立的物件,S0和S1区其中一块用于存放在Minor GC的时候作为复制存活物件的目标空间,另外一块清空。

序列GC(Serial GC)比较适合单CPU的情况,可以通过-XX:UseSerialGC来强行制定;

并行回收GC(Parallel Scavenge),启动的时候按照设定的引数来划定Eden/S0/S1区域的大小,但是在执行时,会根据Minor GC的频率、消耗时间来动态调整三个区域的大小,可以用过-XX:UseAdaptiveSizePolicy来固定大小,不进行动态调整;

并行GC(ParNew)划分Eden、S1、S0的区域上和序列GC一样。并行GC需要配合旧生代使用CMS GC(这是他和并行回收GC的不同)(如果配置了CMS GC的方式,那么新生代预设采取的就是并行GC的方式);

旧生代可用的GC?序列GC(Serial MSC)、并行GC(Parallel MSC)、并发GC(CMS);

关于CMS?

采用CMS时候,新生代必须使用Serial GC或者ParNew GC两种。CMS共有七个步骤,只有Initial Marking和Final Marking两个阶段是stop-the-world的,其他步骤均和应用并行进行。持久代的GC也采用CMS,通过-XX:CMSPermGenSweepingEnabled -XX:CMSClassUnloadingEnabled来制定。在采用cms gc的情况下,ygc变慢的原因通常是由于old gen出现了大量的碎片。

怎么读懂GC日志?GC基本上都是这种格式:回收前区域占用的大小->回收后区域占用的大小(区域设定的大小),占用的时间

假设报错日志如下:

2019-06-22T03:00:53.638+0800: 35333.562: [GC 35333.562: [ParNew (promotion failed): 1877376K->1877376K(1877376K), 15.7989680 secs]35349.361: [CMS: 2144171K->2129287K(2146304K), 10.4200280 sec

s] 3514052K->2129287K(4023680K), [CMS Perm : 119979K->118652K(190132K)], 26.2193500 secs] [Times: user=30.35 sys=5.19, real=26.22 secs]

解释:

1877376K->1877376K(1877376K), 15.7989680 secs young区

2144171K->2129287K(2146304K), 10.4200280 sec old区情况

3514052K->2129287K(4023680K) heap区情况

119979K->118652K(190132K)], 26.2193500 secs perm区情况

[Times: user=30.35 sys=5.19, real=26.22 secs] 整个过程的时间消耗

篇幅有限,这里主要介绍一下概念性的东西,后面介绍下怎么监控GC和GC的一些优化引数,感兴趣的朋友可以关注一下~

6fb4ecea442f30138b41762fbbc65847.jpg

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值