小伙子,你真的清楚 JVM GC ?
序











正文
如何确定垃圾?
前面已经提到 JVM 可以采用 引用计数法 与 可达性分析算法 来确定需要回收的垃圾,我们来具体看一下这两种算法:
- 引用计数法
该方法实现为:给每个对象添加一个引用计数器,每当有一个地方引用它时,引用计数值就+1,当引用失效时,引用计数值就-1,任何时刻引用计数值为0的对象就可以被回收,当一个对象被垃圾收集器收集时,被它引用的对象引用计数值就-1,所以在这种方法中一个对象被垃圾收集会导致后续其他对象的垃圾收集行动。
优点:简单、高效;
缺点:当两个对象相互引用的时候就无法回收,导致内存泄漏。
- 可达性分析法
为了解决对象间相互引用问题,Java 采用了可达性分析法,基本实现思路为:通过一系列 "GC Roots" 对象作为起点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到 "GC Roots" 没有任何引用链相连时,则称该对象是不可达的,此时,该对象还处于缓刑阶段,要真正宣判一个对象为可回收对象,至少要经历两次标记过程。
哪些对象可以作为 "GC Roots" ?
1、通过System Class Loader或者Boot Class Loader加载的class对象
2、处于激活状态的线程
3、栈中的对象
4、JNI栈中的对象
5、JNI中的全局对象
6、正在被用于同步的各种锁对象
7、JVM自身持有的对象,比如系统类加载器等
垃圾回收算法
通过上面面试者的回答,我们已经知道垃圾收集算法主要包括:复制算法、标记清除算法、标记整理算法、分代回收算法,我们来具体看一下:
- 复制算法
该方法实现为:将内存分为大小相等的两块,每次只使用其中一块,当这一块内存满了后将存活的对象复制到另一块上去,把已使用的内存清掉。如图所示:

优点:简单、高效、不会产生内存碎片;
缺点:可用内存减少为原来的一半,造成内存浪费。
- 标记清除算法
该方法实现分为两个阶段,标注和清除,标记阶段找到所有可访问的对象,做个标记 ;清除阶段遍历堆,把未被标记的对象回收。如图所示:

缺点:碎片化严重。
- 标记整理算法
该方法不直接对可回收对象进行清理,而是让所有可用的对象都向一端移动,然后直接清理掉边界外的对象,解决了标记清除算法带来的碎片化问题。如图所示:

- 分代回收算法
分代回收算法是目前大部分 JVM 所采用的方法,其核心思想是根据对象存活的生命周期不同,将内存划分为不同的区域,一般情况下将 GC 堆划分为新生代和老年代;老年代的特点是:对象生命周期较长,每次垃圾回收时只有少量对象需要被回收;新生代的特点是:对象大部分朝生夕死,生命周期短,每次垃圾回收时都有大量对象需要被回收;因此,可以根据不同区域选择不同的算法,使垃圾回收更加合理、高效,如:新生代采用效率较高的复制算法,老年代采用不会产生内存碎片,也不会发生内存浪费的标记整理算法。
垃圾收集器
常用的垃圾收集器都有哪些呢?我们来具体看一下:
- Serial 垃圾收集器
Serial 曾经是 JDK1.3.1 之前新生代唯一的垃圾收集器;Serial 是一个单线程的收集器,在进行垃圾收集的同时,必须暂停其他所有的工作线程,直到垃圾收集结束;但同时 Serial 也是简单高效的,对于限定单个 CPU 环境来说,没有线程交互的开销,可以获得最高的单线程垃圾收集效率。
- ParNew 垃圾收集器
ParNew 是 Serial 多线程版,也使用复制算法,除了使用多线程进行垃圾收集之外,其余的行为和 Serial 收集器完全一样。
- Parallel Scavenge 收集器
Parallel Scavenge 是一个新生代垃圾收集器,同样使用复制算法,也是一个多线程的垃圾收集器,它重点关注的是程序达到一个可控制的吞吐量(吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)),高吞吐量可以最高效率地利用 CPU 时间,尽快地完成程序的运算任务,主要适用于在后台运算而不需要太多交互的任务。
- Serial Old 收集器
Serial Old 是 Serial 垃圾收集器老年代版本,它是个单线程的,使用标记整理算法的收集器。
- Parallel Old 收集器
Parallel Old 收集器是 Parallel Scavenge 的老年代版本,它是多线程的,使用标记整理算法,在 JDK1.6 开始提供使用。
- CMS 收集器
CMS 是一种老年代垃圾收集器,其主要目标是获取最短垃圾回收停顿时间,和其它老年代使用标记整理算法不同,它使用多线程的标记清除算法;其运作过程比较复杂,整个过程分为6个步骤,包括:初始标记(CMS initial mark)、并发标记(CMS concurrent mark)、并发预清理(CMS-concurrent-preclean)、重新标记(CMS remark)、并发清除(CMS concurrent sweep)、并发重置(CMS-concurrent-reset),其中初始标记、重新标记这两个步骤仍然需要暂停其它工作线程,初始标记仅仅只是标记一下 "GC Roots" 能直接关联到的对象,速度很快,并发标记阶段就是进行 "GC Roots" 追踪的过程,而重新标记阶段则是为了修正并发标记期间,因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远比并发标记的时间短。
- G1 收集器
G1 是 JVM 垃圾收集器理论进一步发展的产物,相比与 CMS 收集器,G1 基于标记整理算法,不会产生内存碎片;其次,还可以非常精确控制停顿时间,在不牺牲吞吐量前提下,实现低停顿垃圾回收;G1 收集器避免全区域垃圾收集,它把堆内存划分为大小固定的几个独立区域,并且跟踪这些区域的垃圾收集进度,同时在后台维护一个优先级列表,每次根据所允许的收集时间,优先回收垃圾最多的区域;区域划分和优先级区域回收机制,确保 G1 收集器可以在有限时间获得最高的垃圾收集效率。
小伙子,你真的清楚 JVM GC ?的更多相关文章
- 一夜搞懂 | JVM GC&内存分配
前言 本文已经收录到我的Github个人博客,欢迎大佬们光临寒舍: 我的GIthub博客 学习导图 一.为什么要学习GC&内存分配? 时代发展到现在,如今的内存动态分配与内存回收技术已经相当成 ...
- 如何避免后台IO高负载造成的长时间JVM GC停顿(转)
译者著:其实本文的中心意思非常简单,没有耐心的读者建议直接拉到最后看结论部分,有兴趣的读者可以详细阅读一下. 原文发表于Linkedin Engineering,作者 Zhenyun Zhuang是L ...
- 【转载】Java性能优化之JVM GC(垃圾回收机制)
文章来源:https://zhuanlan.zhihu.com/p/25539690 Java的性能优化,整理出一篇文章,供以后温故知新. JVM GC(垃圾回收机制) 在学习Java GC 之前,我 ...
- JVM GC机制
垃圾收集主要是针对堆和方法区进行. 回收机制: 现在的JVM基本都使用分代回收机制,把堆中内存区域分为新生代,老年代. 新生代: Eden(80%) Survivor0(10%) Survivor1( ...
- 深入浅出 JVM GC(3)
# 前言 在 深入浅出 JVM GC(2) 中,我们介绍了一些 GC 算法,GC 名词,同时也留下了一个问题,就是每个 GC 收集器的具体作用.有哪些 GC 收集器呢? Serial 串行收集器(只适 ...
- 深入浅出 JVM GC(2)
# 前言 在 深入浅出 JVM GC(1) 中,限于上篇文章的篇幅,我们留下了一个问题 : 如何回收? 这篇文章将重点讲述这个问题. 在上篇文章中,我们也列出了一些大纲,今天我们就按照那个大纲来逐个讲 ...
- JVM 自带性能监测调优工具 (jstack、jstat)及 JVM GC 调优
1. jstack:占用最多资源(CPU 内存)的Java代码 https://www.cnblogs.com/chengJAVA/p/5821218.html https://blog.csdn.n ...
- 理解JVM GC
理解JVM GC对于我们把控Java应用有很大的帮助.下面我从运维角度,把网上的JVM相关的资料整理如下,以加深对JVM GC的理解.如有错误的地方,请看官指正. JVM内存使用分类 JVM的内存分区 ...
- Java性能优化之JVM GC(垃圾回收机制)
Java的性能优化,整理出一篇文章,供以后温故知新. JVM GC(垃圾回收机制) 在学习Java GC 之前,我们需要记住一个单词:stop-the-world .它会在任何一种GC算法中发生.st ...
随机推荐
- T4生成实体和简单的CRUD操作
主要跟大家交流下T4,我这里针对的是mysql,我本人比较喜欢用mysql,所以语法针对mysql,所以你要准备mysql的DLL了,同理sqlserver差不多,有兴趣可以自己写写,首先网上找了一个 ...
- react 项目全家桶构件流程
资源:create-react-app.react.react-dom.redux.react-redux.redux-thunk.react-router-dom.antd-mobile/antd. ...
- PATB 1018. 锤子剪刀布
时间限制 100 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CHEN, Yue 大家应该都会玩“锤子剪刀布”的游戏:两人同时给出手势,胜负规则如图 ...
- Mac安装MySQL-python报错解决
Mac安装MySQL-pyhton报错 今天在Mac上安装MySQL-python报错,搜遍网络都说什么mysql config路径问题,但是都不行. 解决方案 一开始遇到的问题是: Complete ...
- Dungeon Master POJ - 2251(bfs)
对于3维的,可以用结构体来储存,详细见下列代码. 样例可以过,不过能不能ac还不知道,疑似poj炸了, #include<iostream> #include<cstdio> ...
- LNet代码分析
源码版本:lustre-release 2.15.55 介绍 LNet是Lustre的网络模块,代码目录分为了lnet和lnd lnet提供了统一的接口 lnd封装了底层驱动,有socklnd(TCP ...
- django启动入口源码分析
manage.py是启动入口,在里面调用execute_from_command_line(sys.argv)方法 def execute_from_command_line(argv=None): ...
- RabbitMQ windows 安装后 此时不应有 \RabbitMQ。
在安装过程中,如果细心实际上在安装的细节显示starting Service后就已经提示这个问题,实际上就是没有注册到RabbitMQ这个服务. 在研究了很久之后才发现原来是安装路径的问题,原先是安装 ...
- redis源码笔记-内存管理zmalloc.c
redis的内存分配主要就是对malloc和free进行了一层简单的封装.具体的实现在zmalloc.h和zmalloc.c中.本文将对redis的内存管理相关几个比较重要的函数做逐一的介绍 参考: ...
- MyBatis 核心配置综述之Executor
目录 MyBatis四大组件之 Executor执行器 Executor的继承结构 Executor创建过程以及源码分析 Executor接口的主要方法 Executor 的现实抽象 上一篇我们对Sq ...