菜鸟学习JVM——垃圾回收算法

75 篇文章 2 订阅
5 篇文章 1 订阅

Java垃圾回收算法

所有的垃圾回收算法都是为了解决三个问题:

  • 哪些内存需要回收
  • 什么时候回收
  • 怎么回收

引用计数法(Reference Counting)

引用计数法原理很简单,给每个对象分配一个计数器,当被引用时就加一,引用失效就减一。计数器为零时,则说明该对象不可能再被使用。引用计数法效率不错,大部分情况下是个不错的算法,但它有一个非常明显的缺点,就是无法回收互相引用的对象,从而引起内存泄露。这也是主流Java虚拟机没有选择它的一个重要因素。
引用计数法
上图中很明显A和B已经不其他对象引用了,但他们互相引用,彼此的计数器都不为零,用引用计数法无法将其回收,从而造成了内存泄露。

标记-清除法(Mark-Sweep)

标记-清除算法是现代垃圾回收算法的思想基础,后面提到的所有算法都是基于该算法的思想。从名字就能看出,该算法分两个阶段进行——“标记”和“清除”。首先通过根对象标记所有可达的对象,然后清除所有未被标记的不可达对象。该算法有一个比较大的缺点,就是容易产生内存碎片。过多的内存碎片对于大对象的内存分配,效率非常低。回收过程如下图:
回收前
回收前
白色表示空闲,灰色表示存活对象,黑色表示垃圾对象
回收后
回收后

什么是可达?

简单的说,就是如果能通过一条路径找到该对象,那么就将该对象称为可达对象。
专业点的说法就是,通过一系列根对象(GC Roots)作为起点,向下搜索,搜索所有的引用路径——引用链(Reference Chain),只要根对象和该对象相连,那么该对象就为可达对象,反之,则为不可达的对象,则证明此对象是不可用的,需要被回收。

复制算法(Copying)

复制算法基于标记-清除算法并对其产生过多内存碎片的缺点进行了优化。复制算法将内存空间分成两等份(如下图的A和B),每次只使用其中的一块,当垃圾回收的时候,将A中的可达对象复制到B中,然后清空A中的所有对象。这样就避免了产生内存碎片的情况,但这种算法的缺点也是显而易见的,那就是太浪费空间。
回收前
A
回收后
B

标记-压缩法(Mark-Compact)

光从名字上就能看出,该算法继承自标记-清除算法。该算法在标记和清除之间又加了一个操作——压缩。首先将标记所有可达对象,然后将所有可达对象压缩(或者叫移动)到内存的一端,最后将边界以外的空间全部清空。这样既避免了产生内存碎片,又不需要空出一块内存空间,一举两得。
回收前
回收前
回收后
回收后

跟上面不同的是:这是同一块内存回收前和回收后的不同状态,而上面是A、B两块不同的内存。

总结(Summary)

JVM中采用的并不是某一种回收算法,而是多种算法组合使用,因为任何一种算法都不是完美的,都有自身的优缺点,有自己适用的场景。需要把他们放到合适的地方,这样才能各尽其能,达到一个最好的效果。

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘水镜

文章写得不错,我要让更多人看到

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值