小课堂 | JVM内存模型(二) – 作者:jordanx

还记得齐安安老师曾经提到的JVM模型知识分享吗?JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。

在上一篇小课堂中介绍到了垃圾回收算法。那么到底什么对象才算是一个垃圾对象?垃圾对象是怎样被GC回收的呢?

Q:GC是什么?

A:是指JAVA/.NET中的垃圾回收器(Garbage Collection),可以帮助程序员去控制内存的释放。当Java虚拟机(VM)或.NETCLR发觉内存资源紧张的时候,就会自动地去清理无用对象所占用的内存空间。

一、如何判定垃圾对象?

1、引用计数法(eference-counting

算法思路:给每个被管理的对象关联一个引用计数器,计数器记录着该对象当前被引用的次数。每当有一个地方引用这个对象时,计数器就+1;每当指向该对象的引用失效时,计数器就-1;任何时刻计数器为0的对象都是不能再被使用的,即对象已“死”。

缺点:很难解决对象之间相互矛盾循环引用的状况。

代码示例:

图片[1]-小课堂 | JVM内存模型(二) – 作者:jordanx-安全小百科图片[2]-小课堂 | JVM内存模型(二) – 作者:jordanx-安全小百科

从控制台输出的[PSYoungGen: 11596K->888K(76288K)]结果可见,GC没有因为test1、test2的互相引用就没有回收,JVM也没有用引用计数法来判断对象是否存活,是否需要被回收。

2、可达性分析算法(Reachability Analysis)

算法思路:通过一系列被称为引用链(GC Roots)的对象作为起始点,沿着这些节点向下搜索,所走过的路径称被为Reference Chain。当一个对象到 GC Roots 没有任何的引用链相连时,说明从 GC Roots 到这个对象不可达,证明此对象不可用。

下图为例:

图片[3]-小课堂 | JVM内存模型(二) – 作者:jordanx-安全小百科

对象Object5-7之间互相引用,但是与GC Roots之间并无可达性,因此可以被标记为垃圾对象,据此被判定为可回收对象。

在Java语言中,以下对象可以作为GC Roots:

◆ 虚拟机栈(栈帧中的本地变量表)中引用的对象

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

◆ 方法区中常量引用的对象

◆ 本地方法栈中(Native方法)引用的对象

在可达性分析算法中不可达的对象,也并非会被GC立刻回收,这时它们暂时处在“缓刑”阶段。一个对象的真正死亡,至少要经历两次标记过程,如果对象不可达,那它将会被第一次标记并进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法

图片[4]-小课堂 | JVM内存模型(二) – 作者:jordanx-安全小百科

Q:什么是finalize()方法?

A:finalize()方法在Object中进行了定义,用于在对象“消失”时,由JVMs进行调用,用于对对象进行垃圾回收,类似于C++中的析构函数,可以覆盖此方法提供垃圾收集时的其他资源;用户自定义时,用于释放对象占用的资源(比如进行I/0操作)

当对象没有覆盖finalize()方法或者finalize()方法已经被JVM调用过,虚拟机会将这两种情况都视为没有必要执行finalize()方法,此时的对象才是真正”死亡”的对象,即垃圾对象。

二、垃圾对象是如何被GC回收的?

当对象被判定为有必要执行finalize()方法,那么这个对象将会被放置在一个叫做F-Queue的队列之中,并在稍后由一个虚拟机自动建立的、低优先级的Finalizer线程去执行它,触发finalize()方法。

finalize()方法是对象逃脱死亡的最后一次机会,稍后GC将对F-Queue中的对象进行第二次小规模标记,如果对象在finalize()中成功拯救自己(只需要重新与引用链上的任何一个对象建立起关联即可),那在第二次标记时它将会被移除出”即将回收”,如果对象这时候还是没有逃脱,那么它就是真的被回收了。

代码示例:

图片[5]-小课堂 | JVM内存模型(二) – 作者:jordanx-安全小百科图片[6]-小课堂 | JVM内存模型(二) – 作者:jordanx-安全小百科

从控制台可以看出,在第一次finalize()方法被调用时,test对象重新可达,因此自救成功,没有被GC所回收;在第二次GC时,由于任何一个对象的finalize()方法都只会被系统自动调用一次,相同的对象在逃脱一次后再次面临回收,它的finalize()方法不会被再次执行,因此逃脱失败,最终被GC回收。

三、本堂小结

本文对Java中使的垃圾回收算算法进行了图文举例说明。GC机制可以在程序性能调优、并发场景下垃圾回收造成性能瓶颈时,进行必要的监控和调节。希望以上这些信息可以更好的帮助程序员们排查出内存溢出、解决内存泄漏等问题,同时为大家带来一些技术上的启发。

也欢迎同学们随时与齐安安联系,分享和交流珍贵知识与宝贵经验!

参考资料

[1] GC回收 百度百科

https://baike.baidu.com/item/GC/66426?fr=aladdin

[2]《深入理解Java虚拟机:JVM高级特性与最佳实践》,周志明,2011年6月

[3]《可达性算法、Java引用 详解》简书,2018年3月

https://www.jianshu.com/p/8f5fa8288d9b

撰稿|齐安安

责编|喵喵

排版设计 | 喵喵

参考资料著作权归作者所有

转载请注明出处

来源:freebuf.com 2020-12-25 10:43:30 by: jordanx

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论