JVM GC详解

一、垃圾定义算法
1.引用计数算法
引用计数法(Reachability Counting,直译为可达性统计),是通过在对象头部分配一个控件来保存该对象被引用次数(Reference Count,直译为查阅统计)。如果该对象被其他对象引用,那么它的引用计数加一,如果删除了该对象的引用,那么引用计数就减1,当该对象引用计数为0时,该对象就会被回收。
该算法是将垃圾回收分摊到了整个应用程序的运行当中,不属于严格意义上的STW(Stop-The-World)垃圾回收机制。
之所以弃用该算法,是因为该算法无法处理这样的情况:首先两个对象相互引用,然后再各自置空自己的引用。此时这两个对象已经没有意义了,但因为相互引用对方,使得双方的引用计数永远都不会为0,那么根据引用计数算法的规则,这两个对象也就永远不会被GC收集器回收。
于是为了解决这个问题,在此基础上演化出了可达性分析算法。

2.可达性分析算法
可达性分析算法(Reachability Analysis,直译为可达性分析),是通过被称为GC Roots(直译为垃圾回收根源)的对象作为起点,从起点开始搜索,搜索走过的路径被称为引用链(Reference Chain),搜索完成后保留所有通过Reference Chain与GC Roots相连的对象,并称这些对象是可达的,然后清理所有不可达对象。
那么哪些对象是GC Root对象呢?
在Java中,GC Root对象包含以下四种:
· 虚拟机栈中引用的对象(未置空的变量)
·方法区中类静态属性引用的对象(static关键字修饰的对象)
·方法区中常量引用的对象(final关键字修饰的对象)
·本地方法栈中引用的对象
本地方法(Native Method):一个Native Method就是一个java调用非java代码的接口,该方法的实现由非java语言实现。
本地方法栈:任何本地方法接口都会使用某种本地方法栈。当线程调用Java方法时,虚拟机会创建一个新的栈帧并压入Java栈。然而当它调用的是本地方法时,虚拟机会保持Java栈不变,不再在线程的Java栈中压入新的帧,虚拟机只是简单地动态连接并直接调用指定的本地方法。

二、垃圾回收算法
1.标记-清除算法
标记清除算法(Mark-Sweep,直译为标记-清除),是一种最基础的垃圾回收算法,就如同名字所说的一样,它首先将内存区域中可回收对象的标记出来,然后清理掉。
但也就是简单的清理掉,并不会对清理出的区域做融合处理,因此它存在最大的问题就是内存的碎片化。于是为了解决这个问题,在此基础上演化出了复制算法。

2.复制算法
复制算法(Copying),它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。例如当前分A、B两块,当A的内存用完了,就将仍然存活的对象复制到B,然后将A的内存空间一次清理掉。这样就解决了标记-清除算法内存碎片化的问题,保证了内存的连续可用。
但代价实在太高,8G的内存只能当4G来用未免太过浪费了。于是从标记-清除算法又演化出了标记-整理算法。

3.标记-整理算法
标记整理算法(Mark-Compact,直译为标记-紧密),是标记清除算法的升级,首先依旧是标记可回收的对象,但并不直接清理,而是让所有存活的对象都向一端移动,再清理掉存活端边界以外的内存区域。
看上去完美无瑕的方法,但每次清理都需要整理所有存活对象的引用地址,内存变更十分频繁,而且在效率上比复制算法要差很多。那难道就没有一种完全适应的方法了吗?答案永远都藏在谜面中,最好的方法往往不是囿于“一种”,而是分而治之。

4.分代收集算法
分代收集算法(Generational Collection,直译为分代收集),严格来说是融合了上述三种算法的一种方法。它将Java堆分为新生代和老年代,又将新生代分为Eden区和Survivor区,其中Survivor区又分为From区和To区。
·Eden区(伊甸园区)
IBM公司的专业研究表明,有将近98%的对象是朝生夕死的,所以在大多数情况下,对象都会在新生代Eden区进行分配,当Eden区空间不足时,虚拟机会发起一次Minor GC(直译为较小的垃圾回收),Minor GC结束后Eden区被情空,此前存活的对象通过复制算法进入Survivor区的From区,如果From区空间不够,则现存对象直接进入Old区,新增对象继续在Eden区进行分配,这也就是Java的内存担保机制。
·Survivor区(幸存者区)
Survivor区是Eden区和Old区的一个缓冲区,每次执行Minor GC,都会将Eden区和From区存活的对象通过复制算放到To区。第二次执行Minor GC时,From区和To区职责对换。
这样做延缓了老年区被填满的速度,也就减少了Major GC的频繁执行。需要注意的是,Minor GC和Major GC都会导致STW(Stop-The-World,停止应用程序的线程),但Major GC导致的延迟基本是可以忽略不计的,因为大部分Eden区的对象都可以被认为是垃圾,很少复制到Survivor区和Old区,对内存的影响很小。
·Old区(老年区)
老年区默认占用着2/3的堆内存空间,只有在Major GC的时候才会被清理。这个区采用的是标记-整理算法。

那么对象是如何进入老年代的呢?
·内存担保机制
详见Eden区后半段。
·大对象
大对象指需要大量连续内存空间的对象。这类对象无论能够存活多久,都会直接进入到老年代。这样做的原因是为了避免在Eden区及Survivor区发生大量的内存复制。
·长期存活对象
虚拟机给每个对象定义了一个对象年龄计数器。当对象在Survivor区的From区和To区之间移动时,即对象每在Survivor区经历一次Minor GC,年龄就会增加一岁。当年龄增加到15岁时,对象就会被转移到老年代。当然,这个15是支持设置的。
·动态对象年龄
虚拟机并不严苛,如果Survivor区空间中相同年龄对象的大小总和大于Survivor区空间容量的一半,那么年龄大于等于该年龄的对象都会直接进入老年区。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值