问题:什么是GC?为什么需要GC?
- GC是JVM中的垃圾回收器,主要用于回收我们不再使用的对象实例。
- 什么情况下不需要GC,程序不创造临时的对象实例时或者内存无限大时。总的来说就是因为计算机资源有限,因此需要GC回收无用资源进行再利用。就像人类为什么需要努力,因为地球资源有限。
问题:GC的STW(Stop the world)是什么?
- GC停止正在执行应用程序业务代码的所有线程,进行空间清理回收。
- STW的发生时间点在程序执行生产的垃圾比GC清理垃圾的速度快,然后内存占用达到了一定的比例时就会执行STW。
- 线程安全问题:并不是所有线程都会立刻中断,一些线程处于一个敏感的代码位时就会继续执行,直到到达最近的一个GC插入的安全点时才会进行中断。
问题:GC中的区域划分是怎样的?
- Eden(伊甸区):所有新创建的对象都会保存在这里。
- Survivor(幸存区):在Eden区的清理存活下来的就会进入Survivor区。
- Tenured(持久区):在Survivor区中经过多次清理后存活下来的数据会进入Tenured区。
- 堆外的区域:元数据(常量、类的信息、源代码)等
问题:GC是怎么清除垃圾(垃圾回收算法)?
- 引用计数发(已摒弃):
- 原理:假设有一个对象A,任何一个对象对A的引用,那么对象A的引用计数器+1,当引用失败时,对象A的引用计数器就-1,如果对象A的计数器的值为0,就说明对象A没有引用了,可以被回收。
- 问题:核心重大的问题是,容易形成环状引用,导致无法清除。
- 三色标记清除法:
- 发展:从双色标记清除法发展而来,解决了由于并发发生的引用无法标记而被清除的问题。
- 原理:一开始所有的数据节点都是白色,然后从根节点开始根据引用链前进,每到一个点(广度优先搜索)标为灰色,直到全部标位灰色;于此同时,同样的算法也从根节点开始根据引用链前进,每到一个点(广度优先搜索)标位黑色,直到全部标位黑色;然后将所有白色的节点清除。
- 图解说明:图片来自“维基百科”
问题:垃圾清除后,如何回收空间?
- 垃圾清除后的空间需要进行整理,不然难以再度分配。如下图所示:
- 空间的回收不同区域方式不一样
- Eden区的将存活的数据放到Survivor区,然后全部数据清空。(复制算法)
- Survivor区存在两个区块S1、S2,每次清理会将一个区块的存活数据复制到另外一个区块中,然后全部清空。(复制算法)
- Tenured区采用整理压缩回收,让所有的对象往一端移动。(标记整理算法)
问题:如何衡量GC的能力
- 吞吐量
- GC的吞吐量衡量有点特殊,它指的是“程序占用CPU工作的时间”与“GC占用CPU工作的时间”比例,默认情况下是99:1。
- 提高吞吐量的方式:
- 使用更大的内存
- 合适的GC算法
- 多线程(不一定有所提高)
- 延迟
- 指的是GC一次STW的时间
- 影响延迟的方式:
- 吞吐量对延迟没有本质的影响
- 多线程
- 使用内存更大
- 内存需求
- 指最终应用对内存的需求
- 需要根据程序了内存使用速度与回收速度比值进行设置。
问题:有哪些常见的垃圾处理器?
- Serial Collector(不建议使用)
- 单线程
- STW时,需要GC全部工作完成才会恢复程序工作线程
- 吞吐量小、延迟大
- Paraller Collector(不建议使用)
- 多线程
- 设计与Serial差不多
- STW时,也是需要GC全部工作完成
- CMS
- 标记时,与工作线程同时运行,支持多核并且多次标记
- 清除时,与工作线程同时运行,采用单核单线程,支持多核(根据任务量)
- 覆盖Serial/Paraller的使用场景
- G1
- 针对大内存,兼顾延迟与吞吐量
- jdk9中的默认垃圾处理器
- G1垃圾收集器将新生代、老年代的物理空间划分取消了
- G1可以精准控制停顿,它把整个堆划分为多个固定大小的区域,每次根据停顿时间去收集垃圾最多的区域。
- G1会智能的分析哪几片区域是靠在一起的,优先目标让区域可以靠在一起,从而达到压缩的目的。
- ZGC
- 低延迟GC
- 最大延迟几个ms,可设置
- 暂停时间不会随着堆的大小、存活对象数目增加
- 它存在风险,可能会挂