2019独角兽企业重金招聘Python工程师标准>>>

1. 引言

垃圾回收器主要需要完成 3 件事:

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

在上一篇博客已经介绍了 java 内存运行时区域的各个部分,其中程序计数器、虚拟机栈、本地方法栈 3 个区域随线程而生,随线程而灭。在这几个区域内就不用考虑回收的问题,因为方法结束或线程结束时,内存自然就随着回收了。

而 java 堆和方法区则不一样,一个接口中的多个实现类需要的内存可能不一样,一个方法中的多个分支需要的内存也可能不一样,我们只有在程序处于运行期间才能知道会创建哪些对象,这部分内存的分配都是动态的,垃圾收集器所关注的是这部分内存。

2. 对象已死吗

在堆内存里面存放着 java 世界中几乎所有的对象实例,垃圾收集器在对堆进行回收前,第一件事就是要确定这些对象之中哪些还「存活」着,哪些已经「死去」(即不可能再被任何途径使用的对象)。

2.1 引用计数算法

引用计数算法是这样的:给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加 1;当引用失效时,计数器就减 1;任何时刻计数器为 0 的对象就是不可能再被使用的。客观地说,引用计数算法的实现简单,判定效率也很高,在大部分情况下它都是一个不错的算法,但是,至少主流的 java 虚拟机里面没有选用引用计数算法来管理内存,其中最主要的原因是它很难解决对象之间相互循环引用的问题

2.2 可达性分析算法

在主流的商用程序语言(Java、C#,甚至包括古老的 List)的主流实现中,都是通过可达性分析来判定对象是否存活的。这个算法的基本思想就是通过一些列的称为「GC Roots」的对象作为起始点,从这个节点开始向下搜索,搜索所走过的路径称为引用链,当一个对向到 GC Root 没有任何引用链相连时,则说明此对象是不可用的,如下图所示。

2.3 再谈引用

判断对象是否存活都与「引用」有关,java 将引用分为强引用、软引用、弱引用、虚引用。四种引用的强度依次逐渐减弱。当内存空间还足够时,这些引用则能保留在内存之中;如果内存空间在进行垃圾收集后还非常紧张,则可以抛弃这些对象。

2.4 生存还是死亡

即使在可达性分析算法中不可达的对向,也并非是「非死不可」,这时候它们暂时处于「缓刑」状态,要真正宣告一个对向死亡,至少要经历两次标记的过程。第一次是进行可达性分析之后发现没有与 GC Roots 相连接的引用链,那么它将被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行 finalize 方法。当对象没有覆盖 finalize 方法或者 finalize 方法已经被虚拟机调用过了,虚拟机将这种情况视为「没有必要执行」。

如果这个对象被判定为有必要执行 finalize 方法,接下来就会被放置一个叫 F-Queue 的队列中,调用对象的 finalize 方法,如果该对象在 finalize 方法中「拯救了自己」--- 只要重新与引用链上的任何一个对象建立连接即可,那么该对象在第二次标记中就会被移除「即将回收」集合。如果这时该对象没有逃脱,那基本上它就真的被回收了。

这里需要注意的是,finalize 方法运行代价高昂,不确定性大,无法保证各个对象的调用顺序,因此,使用 try-finally 或者其他方式都可以做得更好、更及时,所以建议大家完全可以忘掉 java 中有这个方法存在。

3. 垃圾收集算法

3.1 标记-清除算法

最基础的垃圾收集算法是「标记-清除」算法,算法分为「标记」和「清除」两个阶段。之所以说这是最基础的算法是因为后续的算法都是在这个算法的基础上改进的。它主要由两个不足:1. 效率问题,标记和清除两个过程的效率都不高,2. 空间问题,清除之后产生大量不连续的内存碎片,空间碎片太多导致以后再内存中需要分配较大对象时,不得不提前触发另一次垃圾收集

3.2 复制算法

为了解决效率问题,「复制」算法出现了。它将内存分为两块,每次只使用其中的一块,当一块内存用完时,就将还存活的对象复制到另一块内存上,然后再把已经使用过的内存空间一次清理掉。执行过程如下图所示:

只是这种算法的代价太昂贵了,只能使用一半的内存空间。不过问题就是用来解决的,根据 IBM 公司的专门研究表明,新生代中的对象 98% 是「朝生夕死」的,所以不需要按照 1:1 的比例来划分内存空间,而是按照 8:1:1 的比例来划分,每次只使用其中的 9 份,剩下的 10% 作为保留空间在垃圾回收时进行留存对象的复制。这就很好的解决了空间利用的问题。不过,如果留存对象比较多时,就需要依赖其他内存(这里指老年代)进行分配担保了。

3.3 标记-整理算法

复制收集算法在对象留存率较高时就要进行较多的复制操作,效率将会变低。根据老年代的特点,「标记-整理」算法就出现了。标记过程仍然和「标记-清除」算法一样,但是后续步骤不是直接对可回收对象进行整理,而是让所有存活的对象向一端移动,然后直接清理掉端边界外的内存,「标记-整理」算法执行过程如下图所示:

3.4 分代收集算法

这种算法没有什么新的思想,只是根据对象存活周期的不同将对向划分为几块。一般是把 java 堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。

以上就是 java 虚拟机中垃圾收集器的介绍,主要摘自《深入理解java虚拟机》一书。

转载于:https://my.oschina.net/firepation/blog/1930055

java虚拟机之垃圾回收器相关推荐

  1. Java虚拟机的垃圾回收器以及内存分配策略详解

    概述 垃圾回收器(GC)是什么以及为什么我们需要垃圾回收器?? 垃圾回收是Java语言区别于其他语言的一种最为重要的特性之一, 通过垃圾回收器(Garbage Collection)来实现对我们Jav ...

  2. Java虚拟机-经典垃圾回收器

    如果说收集算法是内存回收的方法论,那垃圾收集器就是内存回收的实践者.接下来我们将介绍已经在Jvm里面使用过,或者未来可能会使用的垃圾回收器. 1 Serial 收集器 Serial收集器是最基础,历史 ...

  3. 浅析Java虚拟机的垃圾回收机制(GC)

    目录 一.垃圾回收机制(Garbage Collection) 二.对象回收的时机 引用计数法 可达性分析算法 三.垃圾回收算法 标记-清除算法 标记-复制算法 标记-整理算法 新生代.老年代.永久代 ...

  4. 学习笔记【Java 虚拟机②】垃圾回收

    若文章内容或图片失效,请留言反馈.部分素材来自网络,若不小心影响到您的利益,请联系博主删除. 总目录 学习笔记[Java 虚拟机①]内存结构 学习笔记[Java 虚拟机②]垃圾回收 学习笔记[Java ...

  5. java虚拟机多久触发垃圾回收_每日一问:讲讲 Java 虚拟机的垃圾回收

    昨天我们用比较精简的文字讲了 Java 虚拟机结构,没看过的可以直接从这里查看: 每日一问:你了解 Java 虚拟机结构么? 今天我们必须来看看 Java 虚拟机的垃圾回收算法是怎样的.不过在开始之前 ...

  6. Java虚拟机之垃圾回收详解一

    Java虚拟机之垃圾回收详解一 Java技术和JVM(Java虚拟机) 一.Java技术概述: Java是一门编程语言,是一种计算平台,是SUN公司于1995年首次发布.它是Java程序的技术基础,这 ...

  7. Java中的垃圾回收器的类型概述 《对Java的分析总结》(六)

    1.垃圾收集器的类型 从不同的角度来分析垃圾收集器,可能将其分为不同的类型 1./垃圾收集器是垃圾回收算法(标记-清除算法.复制算法.标记-整理算法.火车算法)的具体实现 2.不同商家.不同版本的JV ...

  8. 深入理解java虚拟机之——垃圾回收(垃圾判断,垃圾收集算法,垃圾收集器)

    java与C++之间有一道动态内存分配和垃圾收集的"墙",墙里面的人想出来,墙外边的人想进去,或许只有骑在墙上才能清楚的了解,墙内墙外都是牢笼. 上面一句出自<深入理解jav ...

  9. java hotspot 默认垃圾回收器_怎么查看服务器默认的垃圾的收集器是哪个?生产环境上如何配置垃圾回收收集器?谈谈你对垃圾收集器的理解?...

    上篇:https://zhuanlan.zhihu.com/p/165998261​zhuanlan.zhihu.com 一.查看默认的垃圾收集器 1.如何查看默认的垃圾收集器 (1)代码演示: pa ...

最新文章

  1. u-boot移植:解决 Retry count exceeded; starting again
  2. java kafka api_kafka java API的使用
  3. Problem M. Mediocre String Problem(Z 函数 + PAM)
  4. java 框架 例子_如何设计Java框架? –一个简单的例子
  5. Qt中的TableWidget初始化表头、行高、选中、自动扩展和接受修改
  6. python执行shell脚本报错_在python中执行shell命令:字符串错误
  7. 数据传输服务 DTS > 产品简介 > 功能特性 > 数据订阅(新版)
  8. Mojoportal 的用户系统
  9. 对js运算符“||”和“”的总结
  10. PreparedStatement 防止 SQL 注入原理
  11. Android 仿京东分类功能实现
  12. python ffmpeg解码视频_利用python+ffmpeg合并B站视频及格式转换的实例代码
  13. 家中买的计算机配置,配置,教您买电脑主要看哪些配置
  14. 阿里云mysql空间不足_阿里云数据库MySQL系统文件导致实例空间满的解决办法
  15. 腾讯云mysql如何设置远程访问_腾讯云主机 MySQL 远程访问配置方法
  16. 电化学线性极化曲线的Tafel外推法(Tafel拟合)得到年腐蚀速率和极化电阻的原理(科研投稿)
  17. 外网使用easyconnect链接校园网
  18. 线性表的创建和基本操作
  19. Windows 反消息钩子(1)
  20. MySQL中distinct和group by性能比较[转]

热门文章

  1. 喜欢熬夜的人注意!出现3大迹象时,说明身体极度危险!
  2. 计算机系统导论第九章,计算机系统导论 -- 读书笔记 -- 第三章 程序的机器级表示 (持续更新)...
  3. python打印文档添加条码_12行代码教会你用python读excel文件,提取数据,生成条形码...
  4. 碱性干电池的内阻测试方法_电池内阻怎么测
  5. 禅道备份功能_禅道数据库备份
  6. 制定交叉编译工具_制作交叉编译工具链的方法总结(详细)
  7. qt5不能添加新文件_VS2017配置Qt5.9教程
  8. smbus使用 树莓派_Linux控制I2C/SMBus设备
  9. eclipse 设置默认编码为Utf-8
  10. html5 职工入职后台管理系统_【开源】Net平台的后台管理系统