文章目录

  • 前言
  • 一、如何判断一个对象是否为垃圾?
    • 1.1、reference count(引用计数)
    • 1.2、reference count(引用计数)存在的问题
  • 二、Root Searching(根可达算法或根搜索算法)
    • 2.1、Root Searching 释义
    • 2.2、根对象(root)的类型
  • 三、三色标记算法原理与存在的问题
    • 3.1、Mark-Sweep(标记清除)
      • 3.1.1、Mark-Sweep(标记清除)应用原理
      • 3.1.2、存在问题-内存碎片化
    • 3.2、Copying(拷贝)
      • 3.2.1、Copying(拷贝)应用原理
      • 3.2.2、存在问题-浪费空间
    • 3.3、Mark-Compact(标记压缩或标记整理)
      • 3.3.1、Mark-Compact(标记压缩或标记整理)应用原理
      • 3.3.2、存在的问题-效率过低
  • 四、垃圾回收器的制定原则
    • 4.1、综合三种算法的 GC
    • 4.2、新生代里面对象的 age 要取值多少?
    • 4.3、堆内存逻辑分区介绍(适用分代垃圾回收器)
    • 4.4、为什么年轻代用 Copying(拷贝)算法?
    • 4.5、 Copying(拷贝)算法在年轻代中的具体应用
  • 总结

前言

本文进入我们进入 JVM 调优系列 2,GC 如何判断对象是否为垃圾,这个是面试中的高频面试题,同时对于 GC 的三色标记算法属于 GC 算法的核心内容,我们将通过算法的应用原理进行深度剖析并分析存在的问题,由此来得出 GC 的制定机制是什么?这里就不再强调重点了,因为到处都是重点!


一、如何判断一个对象是否为垃圾?

1.1、reference count(引用计数)

查看是否有引用指向该对象,有则说明该对象不是垃圾,反之就是垃圾。

我们通过下图的引用对象案例来说明。


如上图所示,我们可以看到一共是存在四个阶段。

  • 第一阶段,有 3 个引用指向该对象,那该对象肯定不是垃圾。
  • 第二三阶段,部分引用消失,分别各有 2 个和 3 个引用指向该对象,那该对象仍然不是垃圾。
  • 第四阶段,没有任何引用再指向该对象,该对象沦为垃圾。这时垃圾回收器就可以将其回收。

1.2、reference count(引用计数)存在的问题

当出现循环引用时,如下图所示:


我们可以看到,三个对象各自指向循环中的另一个对象,但是没有其他引用指向这三个对象,那这三个对象就属于“一堆垃圾”。

那现在我们上面所说的引用计数就不能解决这个该问题,这时我们就需要使用另外一种定位方式——Root Searching(根可达算法或根搜索算法)

二、Root Searching(根可达算法或根搜索算法)

2.1、Root Searching 释义

所谓的“根”即是:所有的程序都是从 main 方法来运行,在 main 方法里面 new 出来的对象即为根对象。

例如:在 main 方法里面我们 new 了一个 list 集合,在 list 集合中我们又可以存放若干其他对象,那我们就称 list 为根对象,我们顺着根的数据结构往下走,只要存在引用指向的对象,那该对象就不是垃圾,反之不存在引用的对象,那该对象就是垃圾。


如上图所示,对象一、二、三、四、五均是存在根对象的引用,对象五、六之间是我们上面所提到的循环引用,对象八不存在引用,故对象六、七、八是垃圾。

2.2、根对象(root)的类型

根对象不仅仅包括我们上面所说的 main 方法里面的对象,属于根对象的还有以下这些:

  • JVM stack
  • native method stack
  • runtime constant pool
  • static references in method area
  • Clazz

三、三色标记算法原理与存在的问题

GC Algorithms 到目前为止一共是有三种,我们将一一进行介绍。

  • Mark-Sweep(标记清除)
  • Copying(拷贝)
  • Mark-Compact(标记压缩或标记整理)

3.1、Mark-Sweep(标记清除)

3.1.1、Mark-Sweep(标记清除)应用原理


如上图所示,我们将可回收的垃圾对象进行标记定位,进行清除即可。将垃圾位变为可用位

3.1.2、存在问题-内存碎片化

算法比较简单,存在缺点,长时间的运行,内存中会存在大量的碎片(碎片化问题)。

何为碎片化?

由上述得知,每一小块可回收内存均需要标记后单独清除,在业务量较大,频繁更新数据的情况下,会有个别的“碎片”长期存在于内存中不去使用,占用资源空间。大量的碎片就会造成查询效率极其低下,所以我们就需要进行处理。

3.2、Copying(拷贝)

如果我们不想出现碎片化问题,我们就可以考虑使用 Copying(拷贝)算法。

3.2.1、Copying(拷贝)应用原理


如上图所示,拷贝算法不管内存有多大,直接一分为二,每次使用仅使用内存的一半,在被使用的内存即将用尽时,将可以使用的存活对象拷贝到另一半内存中,将剩下的可回收的垃圾对象进行回收操作。在另一半内存中进行正常操作,如此循环往复

这种算法每次拷贝完成所有的内存空间都是排列在一起,故不会产生碎片化问题。

3.2.2、存在问题-浪费空间

该算法的优势即是它的劣势,每次仅可以使用一般的内存空间进行操作,相当于浪费了一半的内存空间。

3.3、Mark-Compact(标记压缩或标记整理)

Mark-Compact(标记压缩)的优势在于完善了上述两种算法存在的缺点,既不存在碎片化问题,也不浪费空间。

3.3.1、Mark-Compact(标记压缩或标记整理)应用原理


把有用的存活对象压缩到内存空间的最前面,对可回收的垃圾对象进行处理,如上图所示。

3.3.2、存在的问题-效率过低

由于每次在压缩之间都需要计算空间,导致回收的效率大大降低。

四、垃圾回收器的制定原则

上述三种标记算法可谓是各有利弊,因此在实际应用中,一个垃圾回收器的制定是综合了上述三种算法。

4.1、综合三种算法的 GC


如上图所示,我们将新诞生的对象存放在新生代里。如果新诞生的对象经历了数次垃圾回收仍然没有被回收掉(即每经历一次垃圾回收,该对象年龄 +1,即 age++),当 age 到达一定数值,将该对象置于老年代中进行特殊处理。

4.2、新生代里面对象的 age 要取值多少?

这个即是我们进行 JVM 调优所需要的自行调整的,根据项目需求来设置
同时对于年龄的设置,与具体所使用的 GC 息息相关

  • 如果之前没有对 GC 进行调整或调优的话,默认使用的 GC 为使用的是 PS+PO(Parallel Scavenge+Parallel
    Old),默认年龄为 15。
  • 如果进行调整之后所使用的 GC 是 CMS,那 age 就是 6。
  • 如果使用的 GC 是 G1 的话,则就彻底与 age 无关,因为该 GC 不分代。

4.3、堆内存逻辑分区介绍(适用分代垃圾回收器)

在 4.1 图中,老年代为 tenured。我们将新生代分为三个部分:伊甸园区和两个 survivor 区。

  • 伊甸园区,即对象诞生的地方,存放所有新生的对象,与在西方中我们人类诞生的地方——伊甸园想对应。
  • survivor 区,幸存者区,存放没有在垃圾回收中被回收的对象,有两个,通常命名为 s0、s1 或者 s1、s2 等叫法。

我们一般在年轻代中使用的 GC 算法为 Copying(拷贝),老年代中使用的 GC 算法为 Mark-Sweep(标记清除)和 Mark-Compact(标记压缩或标记整理)。

4.4、为什么年轻代用 Copying(拷贝)算法?

首先我们先考虑 Mark-Sweep(标记清除)和 Mark-Compact(标记压缩或标记整理),上面我们已经说到,这两种 GC 算法的缺点分别是:产生碎片化问题、内存回收效率低

程序产生对象后,该对象很可能会在很短的时间内被回收,根据统计,一次垃圾回收可以回收掉 90% 的对象。在这样的情况下,使用 Mark-Sweep(标记清除)和 Mark-Compact(标记压缩或标记整理)效率就太低了,会造成伊甸园区很快爆满或者大规模碎片化,而新产生的对象产生放进去的效率就会大大降低。

所以在 JVM 设计中,要求年轻代的算法效率是特别高、特别快的。而 Copying(拷贝)算法的效率是最高的,但是浪费了年轻代中至少一半的内存空间。

那我们既要利用好 Copying(拷贝)算法效率高的优势,又要尽量避免内存浪费的问题,怎么解决?

4.5、 Copying(拷贝)算法在年轻代中的具体应用

第一次垃圾回收:首先将 10% 的幸存对象拷贝到第一个 survivor 中,即 s0 中,然后将整个伊甸园区进行清除。这时所有有用对象都存放在 s0 中。如下图所示:


第二次垃圾回收:将伊甸园区中有用的对象拷贝到另一个 survivor 中,即 s1 中,再将之前 s0 中的对象(前提是有用)拷贝到 s1 中,对伊甸园区与第一个 s0 进行垃圾回收。这时所有有用的对象存放在 s1 中。如下图所示:


第三次垃圾回收:再次利用 s0,将之前存活的对象与伊甸园区中产生的新对象存放在 s0 中,对伊甸园区与 s1 进行二垃圾回收。如下图所示:


第 n 次垃圾回收:如此循环往复利用新生代中的伊甸园区与 survivor 区即可。


总结

在本文中我们通过引用计数和根可达两种算法来判断一个对象是否为垃圾,引出在 GC 中的核心——三色标记算法,对于三色标记算法的核心和流程进行了深度剖析,以及其所存在的问题。三色标记算法又为我们引出 GC 的制定原则,GC 对于拷贝算法如何在新生代中运用以提高 JVM 的效率,都是重点内容,这里就不过分强调了。


我是白鹿,一个不懈奋斗的程序猿。望本文能对你有所裨益,欢迎大家的一键三连!若有其他问题、建议或者补充可以留言在文章下方,感谢大家的支持!

JVM 调优 2:GC 如何判断对象是否为垃圾,三色标记算法应用原理及存在的问题?相关推荐

  1. 数据结构与算法+JVM调优和GC常用算法+数据库高级+复杂sql手写

    数据结构 双向链表 二叉排序树 红黑树 散列表 双向链表: 什么是双向链表 双向链表是一种数据结构,是由若干个节点构成,每个节点由三部分构成, 分别是前驱节点,元素,后继节点,且双向链表中的节点在内存 ...

  2. JVM调优总结(6):新一代的垃圾回收算法

    原文出处: pengjiaheng 垃圾回收的瓶颈 传统分代垃圾回收方式,已经在一定程度上把垃圾回收给应用带来的负担降到了最小,把应用的吞吐量推到了一个极限.但是他无法解决的一个问题,就是Full G ...

  3. JVM调优总结(4):分代垃圾回收

    原文出处: pengjiaheng 为什么要分代 分代的垃圾回收策略,是基于这样一个事实:不同的对象的生命周期是不一样的.因此,不同生命周期的对象可以采取不同的收集方式,以便提高回收效率. 在Java ...

  4. 说说关于JVM三色标记算法

    本文来说下关于JVM三色标记算法 文章目录 概述 三色标记算法思想 算法流程 三色标记存在问题 解决办法 CMS回顾 CMS解决办法:增量更新 CMS另两个致命缺陷 G1回顾 G1前置知识 Card ...

  5. JVM 的三色标记算法详解

    本文来说下关于JVM 的三色标记算法. 文章目录 三色标记算法概述 引用计数&可达性分析 分代收集 什么是卡表 卡表的问题 写屏障 伪共享 三色标记算法 基本算法 三色标记算法缺陷 多标 漏标 ...

  6. JVM从入门到精通(十):垃圾回收算法串讲:CMS,G1,三色标记算法

    CMS 并发回收,工作线程和GC线程同时进行,暂停时间短 老年代 分为 四个阶段: 初始标记:需要STW,因为初始的垃圾并不多,因此耗费的时间不长 并发标记:垃圾回收线程和工作线程同时执行.一边产生垃 ...

  7. Go语言实时GC - 三色标记算法

    前言 Go语言能够支持实时的,高并发的消息系统,在高达百万级别的消息系统中能够将延迟降低到100ms以下,很大一部分需要归功于Go高效的垃圾回收系统. 对于实时系统而言,垃圾回收系统可能是一个极大的隐 ...

  8. Java GC如何判断对象是否为垃圾

    查找内存中不再使用的对象 引用计数法 引用计数法就是如果一个对象没有被任何引用指向,则可视之为垃圾.这种方法的缺点就是不能检测到环的存在. 2.根搜索算法 根搜索算法的基本思路就是通过一系列名为&qu ...

  9. JVM调优:GC 参数

    参考: <Memory Management in the Java HotSpot™ Virtual Machine > <Java SE 6 HotSpot[tm] Virtua ...

最新文章

  1. 人工智能的现状与未来
  2. iOS开发之UIWebView
  3. Android — 使用 SharedPreferences 本地保存 key-value 数据
  4. 【XML DOM】解析XML Dom
  5. Celery-------项目目录
  6. 《Pyflink》Flink集群安装,Python+Flink调研
  7. aixdb2安装手册_AIX下安装db2数据库步骤
  8. ORACLE专有模式与共享模式
  9. datetime 比较_MySQL时间类型datetime,timestamp,int如何选择,很多程序员收藏了
  10. 【Linux】虚拟服务器之LVS
  11. MATLAB麦克劳林展开式cosx,用matlab绘制e^x的泰勒展开式的图像
  12. Linux上 如何查找yum安装包所缺缺少的依赖包及报错处理
  13. 51单片机:数码管显示
  14. Android课题研究的主要观点,二、本课题的研究目标、研究内容、主要观点和创新之处.doc...
  15. 解决安装软件时出现“更新错误”或“无法安装”的问题
  16. 最后一公里极速配送(一)
  17. Unity5.x实现简易语音聊天(一) 使用步骤
  18. Web三剑客-CSS笔记
  19. 如何解决路由器延迟问题
  20. GM7150BC是一颗将CVBS/S-Video视频源转换成BT656/601

热门文章

  1. 从实践出发,腾讯云深入解读云端数据库技术
  2. AR热度不在? NO! 三星开发者大会将聚焦AR
  3. java api csdn_java api函数读出当前机器名以及版本号 csdn
  4. delphi7 如何判定dbgrid两行重复_教你如何在服装上加入好看的毛线刺绣花边
  5. c语言静态变量存在堆还是栈,c 类 static 函数 什么样是静态变量?嵌入式C语言的堆栈管理如何实现...
  6. tomcat jsvc java_opts_Tomcat 学习笔记(2) - 使用 jsvc 启动tomcat
  7. libreoffice error while loading shared libraries: libSM.so.6: cannot open shared object
  8. uni-app 微信小程序授权登录
  9. 导入Oracle 数据库镜像,创建Oracle虚拟机_01
  10. WPS重复数据高亮显示