JVM之GC垃圾回收机制

学习JVM中的垃圾回收机制,就是要弄清楚下面三个问题

1、哪些内存需要被回收

2、什么时候回收这些内存

3、如何回收这些内存

针对以上三个问题,逐个分析

一、哪些内存需要被回收

垃圾回收器在判断一个对象是否需要被回收时,有两种算法

1、引用计数法

给每个对象添加一个引用计数器,每当有一个地方引用这个对象时,计数器加1,当引用失效时减1。当对象的引用计数器为0时,就代表这个对象可以被回收了。这种算法判断对象是否应该被回收时的效率非常高,但是无法解决对象之间的相互引用问题,目前主流的JVM都不使用这种算法。

例如A、B对象都有字段instance,A.instance = B,B.instance = A,在引用计数法中,A、B对象的计数器都是1,不会被回收,而在JVM中,很显然他们是两个孤立的对立,应该被回收。

2、对象可达性分析

这种算法可以有效的避免对象循环引用的问题,整体对象实例已一个树呈现,根节点是一个“GC ROOTS”对象,从这个对象开始向下搜索并标记,遍历完这棵树后,未被标记的对象,则是需要回收的对象。如图中Obj4、Obj5需要被回收

一下四种对象作为GC ROOTS对象使用

①虚拟机栈所引用的对象

②方法区中静态属性所引用的对象

③方法区中常量所引用的对象

④本地方法所引用的对象

二、什么时候回收这些内存

1、程序空闲的时候

2、显示调用System.gc()

3、jvm堆内存不足时

三、如何回收这些内存

以下为4中最为常见的垃圾回收算法

1、标记-清除算法

“标记-清除”算法是最基础的算法,分为标记阶段和清除阶段。首先标记出所有需要回收的对象,在标记完成后统一回收掉所有被标记的对象。如图为采用此算法回收前后的内存示意图:

此算法有2个缺点,1、效率问题,标记和清除两个过程,其效率都不高;2、空间问题,图中可以清晰的看出,回收后会产生大量的内存碎片,在需要为一个大对象分配内存空间时,因为找不到合适的连续空间而不得已提前触发下一次GC。

2、复制算法

为了解决标记-清除算法的效率问题,出现的复制算法。它将可用内存按照容量分成两个大小相等的块,每次只使用其中的一块。当这一块内存用完了,就将还活着的对象复制到另一块上,然后清空这一块的内存空间统一清掉。

其优点是每次都是对其中的一块进行内存回收,不会产生内存碎片,在内存分配时,无需考虑碎片问题,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。其缺点也很明显,就是内存缩小了一半,代价过大。

3、标记-整理算法

复制算法在对象存活率高的情况下,每次都要复制大量对象,效率将会变低。所有老年代一般不能直接采用复制算法。针对老年代的特点提出了“标记-整理”算法,其标记过程仍然和“标记-清除”算法一样,但是后续步骤不是将可回收对象直接清除掉,而是让所有存活对象都向内存空间一端移动,然后直接清理掉边界以外的内存空间。

4、分代收集算法

当前商业虚拟机的垃圾回收都采用“分代收集”算法,该算法并不是一种新算法,而是根据对象的存活周期,将内存划分为不同的块,一般是把java堆分为新生代和老年代,然后根据它们的特点,采用不一样的算法。新生代中,每次GC都有大批对象死去,少量对象存活,因此采用复制算法,只需要付出少量对象的复制成本即可。而老年代中,对象存活率高,就必须采用“标记-清除”或者“标记-整理”算法来进行回收。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值