jvm实现垃圾回收—从根儿上理解jvm(四)

回顾

这篇文章将学习jvm的垃圾回收。讲解之前我们先复习一下前三篇文章:

通过这几篇文章,我们对java程序是如何运行起来的,有了深入的理解。接下来,我们继续讲解jvm中另一个比较重要的知识点,垃圾回收。

垃圾回收

首先我们要知道,垃圾要回收的是哪里的对象(内存空间)。java栈中的占用的内存空间,随着栈的pop操作,内存空间也被释放。但是堆中的对象,只是在栈内的引用,并没有被释放,只是没有了引用。我们要回收的就是这些堆中的没有被引用的对象。

为什么要进行垃圾回收

我们知道C和C++程序员是可以操作管理内存的,有更大的自由空间。但这也导致了令他们头疼的问题,就是内存管理。对象的创建和释放是成对的,不然很容易导致内存泄漏(是在计算机科学中,由于疏忽或错误造成程序未能释放已经不再使用的内存 )。java程序员在开发的过程中只会手动的创建对象,很少会主动的考虑释放对象(即使考虑了,也不保证回收)。这样保证了java程序员可以把更多的精力关注代码和业务,其他的一切交给jvm。
回到我们的问题,就是为什么要进行垃圾回收。这个问题反过来问:java作者为什么设计垃圾回收机制来销毁对象,而不是直接方法执行完后,直接销毁堆内的对象,就像栈内的对象一样的设计思想。这样是不是就避免了STW
针对这个问题,没有找到权威的解答,根据自己的理解和大家分享一下:

  • 垃圾回收过程中,不仅会进行对象的回收,还会进行内存的重分配,解决内存碎片问题。
  • 单个方法执行结束后,释放对象,在高并发条件下,可能性能会下降。
    但是在Rust语言中,并没有采用垃圾回收的机制,后续了解了Rust对象销毁原理后,再进行解答。

垃圾回收过程

在进行垃圾回收的过程中,首先需要标记哪些对象是需要存活的,哪些对象是死亡的。这就是垃圾标记阶段。判断对象是否存活一般有两种方式1.引用计数法 2.可达性分析法

引用计数法

引用计数法的原理也很简单,在每一个对象中添加一个引用计数器,每当有其他地方引用到当前对象时,计数器的值就加1;当引用失效时,计数器的值就减1,这样在垃圾回收的时候就直接判断当前对象的引用计数器的值,如果值为0,就表示当前对象已经没有任何地方引用,可以回收,反之若计数器的值不为0,则表示当前对象还被其他地方引用,不回收。
在这里插入图片描述
这个比较简单,大家了解就好,java最终没有采用这种方式,主要原因:对象循环依赖,导致内存泄漏。

可达性分析法

在主流的商用程序语言中(Java和C#),都是使用可达性分析算法判断对象是否存活的。
可达性分析算法的思想:从一个被称为GC Roots的对象开始向下搜索,如果一个对象到GC Roots没有任何引用链相连时,则说明此对象不可用。
在这里插入图片描述
由上图,我们可以看出 6 、7和8是不可达的,就是我们需要回收的对象。

垃圾回收算法

在了解完垃圾回收主要发生的区域以及如何判断对象是否可被回收之后,再需要了解的就是垃圾回收算法,垃圾回收算法就会使用到以上提到的可达性分析算法标记对象是否可被回收。
通过visualvm 可以看到jvm的堆对象是分代的(堆内对象是分代存储的(Eden,S0,S1和old)新生代和老年代。)。
在这里插入图片描述
新生代内对象的特点是,大部分朝生夕死,也就是大部分的对象是需要回收的。
老年代内对象特点是,大部分是存活的对象。

标记清除算法

在这里插入图片描述
如图:该算法分为两阶段:第一阶段,标记哪些对象是可回收对象(死亡对象),第二阶段,将死亡对象清除。
优点:执行速度快,效率高
缺点:造成内存碎片

标记复制算法

在这里插入图片描述
如图:该算法现将内存一分为二,然以后将存活的对象直接复制到另一份内存块。
优点:不会造成内存碎片。
缺点:内存使用率不高(一块内存用于复制)。

标记整理算法

在这里插入图片描述
如图:在标记清除算法的基础上增加了整理压缩(解决了内存碎片问题)
缺点:执行效率低。

分代算法(以上算法的综合使用)

以上的GC回收算法都各有利弊,实际使用中,根据内存区域的划分以及其特点,HotSpot不单一采用以上的算法,而是根据堆区不同分代,分别采用以上算法,这种算法被称为分代算法。

由于Java对象具有朝生夕死的特点,堆区一般划分为新生代(年轻代)和老年代(年老代)。新生代对象生存周期短暂,老年代对象生成周期较长:

新生代对象存活周期短,每次只有少量对象存活,使用复制算法比较适宜。所以HotSpot中将新生代分为Eden和Survivor区域。
老年代对象存活时间长,每次GC后,大部分对象都存活。所以使用标记整理算法。

小结

jvm是java程序运行的基石,学好jvm对能更好的理解java程序是如何运行起来的。通过四篇文章,我们对jvm运行的内部原理,有了深入的理解。接下来的文章我将陪大家一起总结java程序如何运行起来的做一个整体概括。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值