谈谈 JVM 垃圾回收机制
前言
垃圾回收需要思考三件事情,哪些内存需要回收?什么时候回收?如何回收?
一、哪些内存需要回收
JVM 的内存区域中,程序计数器、虚拟机栈和本地方法栈的生命周期是随线程而生,随线程而灭的。这几个区域的内存分配和回收都具有确定性,不需要过多考虑回收问题,当方法或线程结束时,内存自然就跟着回收了。
Java 堆和方法区是具有不确定性的,比如一个方法根据不同的条件执行可能需要的内存是不同的。只有处于运行期才能知道需要创建哪些对象,创建多少对象,这部分的内存分配和回收是动态的,垃圾回收所关注的就是这部分内存。
二、对象何时会“死亡”
Java 堆中存放了几乎所有的对象实例,垃圾回收器在进行回收前,需要判断哪些对象“存活”,哪些对象“死亡”,“死亡”的对象才会被回收。
1. 引用计数法
给对象中添加一个引用计数器:
- 每当有一个地方引用它,计数器就加 1;
- 当引用失效,计数器就减 1;
- 任何时候计数器为 0 的对象就是不可能再被使用的。
这个方法实现简单,效率高,但是目前主流的虚拟机中并没有选择这个算法来管理内存,其最主要的原因是它很难解决对象之间相互循环引用的问题。
2. 可达性分析算法
通过一系列被称为GC Roots的根对象作为起始节点集,从这些节点开始,通过引用关系向下搜寻,搜寻走过的路径称为“引用链”,如果某个对象到GC Roots没有任何“引用链”相连,就说明该对象不可达,即可以被回收。
如下图,Object 5、Object 6、Object 7 虽有关联,但是到GC Roots是不可达的,因此会被判定“死亡”。

Java 中固定可作为GC Root对象的有:
- 虚拟机栈的栈帧中的本地变量表中引用的对象,如,参数、局部变量、临时变量等。
- 方法区中类静态属性引用的对象,如,类中的静态变量。
- 方法区中常量引用的对象。
- 本地方法栈中 JNI(也就是native方法)引用的对象。
- Java 虚拟机内部的引用,如基本数据类型对应的 Class 对象、常驻异常、系统类加载器等。
- 被同步锁持有的对象。
除了这些固定的还有一些临时性加入的,有兴趣的可以看下《深入理解 Java 虚拟机》。
上述两种方法都需要了解引用,详细介绍见Java引用。
3. 方法区的回收
不要求虚拟机在方法区进行垃圾回收,在 Java 堆中,尤其是在新生代中,常规进行一次垃圾收集通常可以回收70%至99%的内存空间,相比之下,在方法区进行回收的“性价比”较低。该区域的垃圾回收主要是两个部分,废弃的常量和不再使用的类。
3.1 废弃常量
假如在字符串常量池中曾存在字符串 "java",如果当前没有任何字符串对象引用该字符串常量的话,就说明常量 "java" 就是废弃常量,如果这时发生内存回收的话而且有必要的话,"java" 就会被系统清理出常量池了。
3.2 不再被使用的类
类需要同时满足下面 3 个条件才能算是 “不在被使用的类” :
- 该类所有的实例都已经被回收,也就是 Java 堆中不存在该类的任何实例。
- 加载该类的 ClassLoader 已经被回收。
- 该类对应的 java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
三、垃圾回收算法
这里整理的均为“追踪式垃圾回收“,也成为”间接垃圾回收“。
1. 分代回收
Java 堆的区域划分如下图,被分为新生代、老年代、永久代或元空间,具体划分为五大块区域,不同的 GC 会针对不同的区域进行垃圾回收。

GC类型一般有以下几大类:
| 分类 | 说明 |
|---|---|
| Minor GC | 也称“Young GC”,只针对新生代进行的垃圾回收。 |
| Major GC | 也称“Old GC”,只针对老年代进行的垃圾回收 |
| Mixed GC | 针对新生代和部分老年代进行垃圾回收,部分垃圾收集器才支持。 |
| Full GC | 针对整个Java堆和方法区进行的垃圾回收,耗时最久的GC |
2. 标记-清除算法
最早出现的垃圾回收算法,分为“标记”、“清除”两个阶段。可以标记存活的对象,也可以标记要回收的对象。
该算法有两个缺点:
- 是执行效率不稳定,随着对象的增多,标记效率会越来越低;
- 内存空间产生很多碎拼,浪费空间,分配大对象时可能需要重新触发垃圾回收。
标记-清除算法执行过程如下图:

3. 标记-复制算法
简称复制算法,为了解决标记-清除算法面对大量可回收对象执行效率低的问题,就是将内存分成两个区域,每次只使用其中一个区域,当该区域内存满了之后,会将还存活的对象复制到另一个区域,然后将原区域直接清理掉。
该算法有两个缺点:
- 对象存活率过多时,会影响复制的效率;
- 一半内存不使用,浪费了大量空间。
标记-复制算法执行过程如下图:

由于 Java 的新生代对象存活率不高,所以一般针对新生代的垃圾回收使用标记-复制算法。
如下图,将新生代分为内存较大的Eden,和两块内存较小的Survivor。每次分配内存只使用Eden和其中一个Survivor,我们假设第一次分配内存是Eden、Survivor 0。
- 发生 GC 时,将使用的
Eden、Survivor 0中存活的对象一次性复制到Survivor 1中,然后清理掉Eden、Survivor 0内存。 - 这时分配的内存就变成了
Eden、Survivor 1,周而复始。
注意:当Survivor不足以容纳轻 GC 之后的对象时,就需要依赖老年代来进行内存分配了。

4. 标记-整理算法
标记完存活对象以后,让所有存活对象都向内存空间的一端移动,然后在清理掉边界以外的内存。
标记-整理算法执行过程如下图:

这种涉及到了对象的移动,如果移动存活对象,尤其是老年代这种每次回收都有大量对象存活的区域,会耗时很多,并且对象移动操作会全部暂停用户应用程序才能进行,这样会产生停顿时间。
这种停顿被称为
Stop The World。
5. 标记-清除-整理算法
先使用标记-清除算法进行垃圾回收,暂时容忍内存碎片的存在,直到碎片过多影响对象分配时,在进行标记-整理算法进行回收,获得规整空间。
四、经典垃圾收集器
下图展示了 7 种经典垃圾收集器,若两两出现互连情况,则表明两者它们可以搭配使用。
- 单线程收集器 Serial、Serial old
- 并行收集器 Par New、Parallel Scavenge、Parallel old
- 并发收集器 CMS、G1

1. Serial 收集器
最基本、历史最早的垃圾收集器了。单线程的收集器,收集垃圾时,必须暂停其他所有工作线程,也就是必有停顿,使用复制算法。
2. Par New 收集器
多线程并行版本的 Serial 收集器,收集垃圾时,必须暂停其他所有工作线程,也就是必有停顿,使用复制算法。
3. Parallel Scavenge 收集器
类似 Par New 收集器,但关注点是达到一个可控的吞叶量,使用复制算法。
吞吐量公式:

吞吐量示例:
代码运行 95 秒 , 垃圾收集器运行 5 秒 , 那么吞吐量就是 $\frac{95}{95 + 5} = 0.95$
4. Serial old 收集器
Serial 收集器的老年代版本,单线程收集器,使用标记-整理算法。它主要有两大用途:
- 在JDK1.5及以前的版本中与 Parallel Scavenge 收集器搭配使用;
- 作为CMS收集器的后备方案。
5. Parallel old 收集器
Parallel Scavenge收集器的老年代版本。使用多线程和标记-整理算法。在注重吞吐量以及CPU资源的场合,都可以优先考虑 Parallel Scavenge收集器和Parallel Old收集器(JDK8默认的新生代和老年代收集器)。
6. CMS 收集器
是一种以获取最短回收停顿时间为目标的收集器。它非常符合在注重用户体验的应用上使用,它是HotSpot虚拟机第一款真正意义上的并发收集器,它第一次实现了让垃圾收集线程与用户线程(基本上)同时工作。
整个过程分为5个步骤:初始标记→并发标记→重新标记→并发清理→并发重置。
7. G1 收集器
基于标记整理算法实现,运作流程主要包括以下:初始标→并发标记→最终标记→筛选回收,不会产生空间碎片,可以精确地控制停顿,可以支持用户设置期望停顿时间。
不追求一次性将 Java 堆清理干净,只要垃圾收集的速度赶得上对象分配的速度即可。
参考:
[1] 周志明. 深入理解 Java 虚拟机(第3版).
谈谈 JVM 垃圾回收机制的更多相关文章
- 谈谈JVM垃圾回收机制及垃圾回收算法
一.垃圾回收机制的意义 Java语言中一个显著的特点就是引入了垃圾回收机制,使c++程序员最头疼的内存管理的问题迎刃而解,它使得Java程序员在编写程序的时候不再需要考虑内存管理.由于有个垃圾回收机制 ...
- JVM垃圾回收机制和常用算法
由于疫情的原因,所以目前一直在家远程办公,所以很多时间在刷面试题,发现2019大厂的面试虽然种类很多,但是总结了一下发现主要是这几点:算法和数据结构. JVM.集合.多线程.数据库这几点在面试的时候比 ...
- JVM垃圾回收机制总结:调优方法
转载: JVM垃圾回收机制总结:调优方法 JVM 优化经验总结 JVM 垃圾回收器工作原理及使用实例介绍
- JVM内存管理和JVM垃圾回收机制
JVM内存管理和JVM垃圾回收机制(1) 这里向大家描述一下JVM学习笔记之JVM内存管理和JVM垃圾回收的概念,JVM内存结构由堆.栈.本地方法栈.方法区等部分组成,另外JVM分别对新生代和旧生代采 ...
- JVM垃圾回收机制概述
JVM垃圾回收机制概述 1.定义 是指JVM用于释放那些不再使用的对象所占用的内存. 2.方式 2.1引用计数(早期) 当引用程序创建引用以及引用超出范围时,JVM必须适当增减引用数.当某个对象的引用 ...
- Java虚拟机学习笔记——JVM垃圾回收机制
Java虚拟机学习笔记——JVM垃圾回收机制 Java垃圾回收基于虚拟机的自动内存管理机制,我们不需要为每一个对象进行释放内存,不容易发生内存泄漏和内存溢出问题. 但是自动内存管理机制不是万能药,我们 ...
- JVM基础系列第8讲:JVM 垃圾回收机制
在第 6 讲中我们说到 Java 虚拟机的内存结构,提到了这部分的规范其实是由<Java 虚拟机规范>指定的,每个 Java 虚拟机可能都有不同的实现.其实涉及到 Java 虚拟机的内存, ...
- 前端面试:谈谈 JS 垃圾回收机制
摘要: 不是每个人都回答的出来... 最近看到一些面试的回顾,不少有被面试官问到谈谈JS 垃圾回收机制,说实话,面试官会问这个问题,说明他最近看到一些关于 JS 垃圾回收机制的相关的文章,为了 B 格 ...
- JVM内存管理、JVM垃圾回收机制、新生代、老年代以及永久代
内存模型 JVM运行时数据区由程序计数器.堆.虚拟机栈.本地方法栈.方法区部分组成,结构图如下所示. JVM内存结构由程序计数器.堆.栈.本地方法栈.方法区等部分组成,结构图如下所示: 1)程序计数器 ...
- JVM 垃圾回收机制和常见算法和 JVM 的内存结构和内存分配(面试题)
一.JVM 垃圾回收机制和常见算法 Sun 公司只定义了垃圾回收机制规则而不局限于其实现算法,因此不同厂商生产的虚拟机采用的算法也不尽相同.GC(Garbage Collector)在回收对象前首先必 ...
随机推荐
- 帕鲁重大更新!macOS 竟然也能玩了
近日,<幻兽帕鲁>迎来了 v0.2.1.0 大版本的更新. 本次更新的最大亮点是新实装的突袭头目系统.玩家可以在 "召唤祭坛" 献祭石板,从而召唤强大的突袭头目.其中, ...
- C语言 02 安装
C 语言的编译器有很多,其中最常用的是 GCC,这里以安装 GCC 为例. Windows 这里以 Windows 11 为例 官方下载地址:https://www.mingw-w64.org/ 选择 ...
- sql 语句系列(月份的第一个星期的星期一和最后一个星期的星期一)[八百章之第二十一章]
mysql select y.first_monday,CASE MONTH(ADDDATE(y.first_monday,28)) when mth then ADDDATE(y.first_mon ...
- 【Nano Framework ESP32篇】WS2812 彩色灯带实验
地球人皆知,许多物联网教程作者的心中都深爱着一灯大师,所以第一个例程总喜欢点灯,高级一点的会来个"一闪一闪亮晶晶".老周今天要扯的也是和灯有关的,但不单纯地点个灯,那样实在不好玩, ...
- vue项目node-scss装不上问题( vue执行npm install报错: Can‘t find Python executable “python“, you can set the PYTHON env variable
一.描述从网上下载的一个Vue模板项目,导入VsCode,执行npm install命令后,报错了,报错的信息是node-sass安装失败,同时提示需要python环境的错误信息,这是因为安装node ...
- Kubernetes 部署集群1.28.2版本(无坑)
初步搭建一个一个主节点和两个从节点Kubernetes 1.28.2 集群.先准备好机器 | host | hostname | os | role | hardware | | --- | --- ...
- 中国大陆地区维护的Linux操作系统
Linux开源生态丰富,中国大陆地区基于CentOS停服,依托阿里云.腾讯云.华为云三大私营企业,相继发布了自己的开源Linux定制版,很高兴的是他们只是改个名字并没有选择闭门造车,只是官网还是很不耻 ...
- 力扣273(java)-整数转换英文表示(困难)
题目: 将非负整数 num 转换为其对应的英文表示. 示例 1: 输入:num = 123输出:"One Hundred Twenty Three"示例 2: 输入:num = 1 ...
- 阿里云全站加速DCDN重磅发布!打造新一代加速引擎
简介: 新一代的加速引擎DCDN,安全.高效.可计算 在数字化转型变革逐步深入的当下,安全高效成为企业上云.全球化部署的关键需求. 随着应用场景复杂度不断提升.业务需求差异化发展,为了给企业提供更完善 ...
- 【云原生】拿下 Gartner 容器产品第一,阿里云打赢云原生关键一战!
近日,Gartner 发布 2020 年公共云容器报告,据报告显示,阿里云和 AWS 拥有最丰富的产品布局,覆盖 9 项产品能力,并列排名第一. 据 Gartner 分析师评论,阿里云拥有丰富的容器产 ...