JVM垃圾收集(GC)

简介: 参考文献:周志明《深入理解Java虚拟机》第二版因为 Java 具有自动垃圾回收机制,所以,垃圾收集(Garbage Collection,GC),是 Java 技术的核心之一,是...

参考文献:周志明《深入理解Java虚拟机》第二版

因为 Java 具有自动垃圾回收机制,所以,垃圾收集(Garbage Collection,GC),是 Java 技术的核心之一,是每一个 Java 程序员必知必备的一项技术,为了深入掌握 Java 技术,我们必须学习 JVM 中的 GC 是如何实现的

GC 中包含三个主要的问题:

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

我们对这三个问题逐一讨论

哪些内存需要回收?

首先我们应该清楚,在 Java 内存运行时区域的各个部分中,程序计数器(PC)、虚拟机栈(VM Stack)、本地方法栈(NM Stack)三个区域随线程而生,随线程而灭,这几个区域的内存分配和回收都具有确定性,不必过多考虑 GC 问题。而 Java 堆(Java Heap)和方法区(Method Area)就不一样了,因为,一个接口中的多个实现类需要的内存可能不一样,一个方法中的多个分支需要的内存也可能不一样,我们只有在程序运行中才能知道会创建哪些对象,所以这部分内存的分配与回收是动态的,我们需要在 Java 堆方法区 中研究 GC 问题

需要回收哪些内存,就是如何判定对象的“生”(正在被使用)或“死”(不会再被使用),有两种判定方法:

引用计数法

这是一种简单直接的判定方法,具体实现就是:给对象中添加一个引用计数器,每当它被引用时计数器就加 1 ;引用失效时,计数器就减 1,所以,计数器值为 0 的对象,就是已经没用的对象,可以被回收
这种方法实现简单,判定高效,但是却几乎不被 JVM 使用,原因是它有一个致命缺陷:无法解决对象相互循环引用问题,比如,有两个已经没用的对象 objA 和 objB ,它们虽已经不会再被程序引用,但是它们相互引用 objA.instance = objB; objB.instance = objA; 这样一来,它们的引用计数值都不为 0,无法被清理掉,它们就会一直占用空间

可达性分析法

这个判定对象“生死”算法是目前比较主流的 ,这个算法的基本思路是通过一系列的称为 GC Roots 的对象作为起始点,然后从这些结点向下搜索,搜索过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连(或是说从 GC Roots 不可达),就证明对象不可用,可以清除了
这里写图片描述
如图,Object 6, 7, 8 都是可清除的对象

那么,GC Roots 具体都是什么呢?它包括下面几种:

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象
  • 方法区中类静态属性引用的对象
  • 方法区中常量的引用对象
  • 本地方法栈中 JNI (即一般说的 Native 方法)引用的对象

ps. JVM规范中没有要求方法区必须有 GC,因为“性价比”低,过于复杂会影响性能,而且一些 JVM 将 Java 堆与方法区合为一体,因此,在本文中不讨论方法区的GC

什么时候回收?

因为 GC 主要发生在 Java 堆中,要回答这个问题就必须先明白 Java 堆的分区和 GC 的分类
Java 堆分为 新生代老年代 两个区,其中新生代又分为 一个 Eden区和 两个 Survior区(from Survior 和 to Survior),分出两个 Survior区是因为新生代回收算法采用 复制算法(后文会讲解)
GC 分为 新生代 GC(Minor GC)老年代 GC(Major GC / Full GC)
新创建的对象实例都会先进入 Eden区, 当 Eden区的空间不够新对象存入时就会触发 Minor GC,经历一次 Minor GC 而未被清除的对象会被存入 Survior区,之后每经历一次 Minor GC 未被清除,对象的“年龄”就会增长一岁,当岁数足够时,就会进入老年代,当老年代满时,就会触发一次 Full GC
因为 Java 对象大多都是朝生夕灭,所以 Minor GC 非常的频繁,一般速度也比较快,Full GC 不常发生,而且速度要比 Minor GC 慢 10 倍以上

如何回收?

这个问题是十分重要的,它就是说 GC 算法是如何实现的,GC 算法有很多,我们在此讨论最经典的几个

标记-清除算法

这是最简单基础的 GC 算法,它分为“标记”、“清除”两个阶段,就是简单的标记出可回收对象,然后将其清除,不做其他操作
这里写图片描述
这个方法虽简单,但是它有两个弊病:
① 效率不高
② 会产生大量空间碎片(如上图)
大量的空间碎片会导致大对象进入时,无法找到足够连续的内存空间,不得不触发一次 Minor GC

复制算法

它将可用内存分为大小相等的两部分,每次只使用其中一块,当这一块用完了,就将还存活的对象复制到另一个上面,然后再把使用过的内存空间一次清理掉,这种算法简单高效,不会产生内存碎片,但是代价是内存容量减小了一半,但是因为它的高效快速,所以被应用在 Minor GC 中
这里写图片描述

标记-整理算法

这个算法就是在标记-清除算法的基础上加入了整理内存空间的功能,它不会产生内存碎片,也不会牺牲空间,但是因为它要逐个整理导致回收速度缓慢,所以它被应用在老年代 Full GC 中
这里写图片描述

目录
相关文章
|
3月前
|
算法 Java
太狠了!阿里技术专家撰写的电子版JVM&G1 GC实战,颠覆了传统认知
JVM是Java语言可以跨平台、保持高发展的根本,没有了 JVM, Java语言将失去运行环境。针对 Java 程序的性能优化一定不可能避免针对JVM 的调优,随着 JVM 的不断发展,我们的应对措施也在不断地跟随、变化,内存的使用逐渐变得越来越复杂。所有高级语言都需要垃圾回收机制的保护,所以 GC 就是这么重要。
|
3月前
|
算法 Java
JVM GC和常见垃圾回收算法
JVM GC和常见垃圾回收算法
48 0
|
3月前
|
缓存 监控 算法
jvm性能调优实战 - 39一次大促导致的内存泄漏和Full GC优化
jvm性能调优实战 - 39一次大促导致的内存泄漏和Full GC优化
71 0
|
4月前
|
存储 缓存 算法
JVM(四):GC垃圾回收算法
JVM(四):GC垃圾回收算法
|
3月前
|
架构师 Java
jvm性能调优实战 - 35电商APP后台系统如何对Full GC进行深度优化
jvm性能调优实战 - 35电商APP后台系统如何对Full GC进行深度优化
52 0
|
3月前
|
存储 监控 算法
垃圾回收器、垃圾回收算法、空间分配担保、JVM调优、GC回收对象的过程
垃圾回收器、垃圾回收算法、空间分配担保、JVM调优、GC回收对象的过程
|
3月前
|
存储 分布式计算 前端开发
jvm性能调优实战 - 26一个每秒10万并发的系统如何频繁发生Young GC的
jvm性能调优实战 - 26一个每秒10万并发的系统如何频繁发生Young GC的
63 0
|
16天前
|
算法 Java UED
【五一创作】值得一看的JVM垃圾收集器
【五一创作】值得一看的JVM垃圾收集器
|
1月前
|
算法 Java
JVM中如何实现垃圾收集
JVM中如何实现垃圾收集
|
2月前
|
算法 Java
深入理解JVM - 解读GC日志
深入理解JVM - 解读GC日志
52 0