阅读 188

JVM垃圾回收算法的基础设计理论

知识不是孤立的,且不应该被孤立,你要试图去找到它们之间的联系,以此去更好的运用它,这是我鼓励我自己的话,希望与你们共勉。

今天我们来说说垃圾回收的基础设计理论,这是了解垃圾回收算法,了解GC机制的前提,也是每个进行JVM调优的程序员的必修课,你要它帮你干什么,你得先了解它需要什么,读完本篇文章,你能了解到垃圾回收的基础算法的设计原理。

分代搜集理论

我们绝大部分垃圾收集器都是遵循分代收集理论进行设计的,分代收集理论是一种人们根据实际程序运行的规律发现的一种规律,该规律和对象有关,这个规律有如下两个假说:

  1. 绝大多数对象都是朝生夕灭的

  2. 如果一个对象能扛过多次GC,那就说明其越难消亡。

试想一下如果我们能把对象按照年代划分,刚出生的放在新生代,因为很快就会消亡,所以我们只需要标记出少量存活对象,然后以较低代价进行回收,然后把多次GC的对象放一起,让VM以极低的频率进行回收,这样就同时兼顾了垃圾回收的时间开销和内存空间的有效利用。

这样我们就可以根据不同的区域发展出Full GC、Young GC、Major GC以及和各自区域对象存亡特征相匹配的垃圾回收算法:标记-复制标记-清除标记-整理

跨代引用假说

分代收集理论虽然带来了内存管理的便利,但划分java区域有一个很明显的问题就是:对象并不是孤立的,对象之间会存在跨代引用。这样我们在对新生代进行垃圾回收之前,除了遍历GC ROOTS 之外,还要遍历老年代中的对象,来保证可达性分析结果的准确性,但这无疑给内存回收造成性能上的负担。

因此我们需要更新一条跨代引用假说上去,这就是跨代引用假说,我们可以假设两个对象之间存在跨代引用,那它们之间的关系就是要么同生,要么同死,因为如果是老年代代的对象引用了年轻代的对象,那就会导致年轻代的对象难以消亡,那必然会在多次GC之后进入老年代,这样跨代引用也就不存在了。

因此,我们没必要为了少量的跨代扫描整个老年代,我们只需要在年轻代添加一个全局的数据结构:记忆集,用来记录老年代哪块发生了跨代引用,然后发生Minor GC时,我们只需要把对应的存在跨代引用的区域加入GC Roots进行扫描即可,这样就不用扫描整个老年代了。

对象判决方法

引用计数法

算法原理

引用计数法的算法原理比较简单,有对象引用就在对象头分配的一块用于引用次数计数的位置上更新次数,有对象引用,就正向加,无引用,就反向减,当引用计数为0时,该对象就会被清理。

比如:我创建两个对象A和B,然后指向它们的分别是a和b,

image.png然后,我改变引用关系,把原来指向A的换成指向B

image.png

引用计数法在实现的时候,如果当前对象的引用为0时,就要对其进行回收,但是会找到和它相关的所有对象,都把它们的引用计数减1,如果有对象减为0时也进行回收,但是引用计数法处理不了循环引用,其实这也很好理解,引用计数法处理的都是外部引用,即外部对象失去时,引用计数减1,但内部对象由于有循环引用的逻辑关系,不管你怎么减,它的引用计数始终是1,所以会造成内存泄漏。

image.png

可达性分析法

可达性分析法就是说有一个GC Roots,然后我们从这个对象出发,会搜索到一系列引用链,这些链上有对象关系的对象证明对象可达,反之,不可达,证明对象应该被回收。

image.png

在java体系中,GC Roots的对象是固定的,如下: 在虚拟机栈中引用的对象 在方法区中静态属性引用的对象 在方法区中常量引用的对象 在本地方法栈中JNI引用的对象 java虚拟机内部的引用 所有被同步锁持有的对象


作者:CocaCoder
链接:https://juejin.cn/post/7027736925293412388


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐