1.什么是GC
GC就是垃圾回收的缩写, 目的就是在java虚拟机中 用于管理和回收堆内存的对象, 当创建对象时,jvm会将其存储在堆内存, 如果这个对象没有被任何引用所使用,称之为不可达对象,这种对象就是GC准备回收的目标。GC通过一定的策略来实现这个目标,它的策略主要包含两种(1.GC标记算法 2.GC回收算法)
2.GC标记算法 --面试题 重点
2.1引用计数法
引用计数法是一种最简单的标记算法,目的是用于追踪对象是否可用,每个堆内存存储的对象都会有一个引用计数器,当有一个引用指向它 计数器+1 如果少了一个引用 计数器-1 当计数器为0时 就可以标记成可回收对象
- 缺点:无法处理循环引用的问题,如果多个对象之间相互引用 计数器永远不会为0除非有外力介入否则不会被回收 很容易导致内存泄漏
2.2可达性分析法:
可达性分析法用于判断对象是否可达的一种算法,在jvm中或者其他支持垃圾回收的语法使用非常广泛。它的实现原理是:首先有一个GC ROOT(根)作为整个对象访问链的入口从根开始向下搜索(深度优先搜索)对象引用图,这样就会形成如下图引用链,不在引用链上的对象就会标记成可回收对象
2.3三色标记法:
三色标记法也是jvm一种非常重要的标记算法,在该算法中,将堆内存的对象分成三种颜色,通过不同的颜色来区分是否可达
- 白色:表示垃圾回收器未被访问过的对象,这些对象可能是垃圾
- 灰色:表示垃圾回收器已经标记为可达了,但是和其关联的对象没有被全部扫描
- 黑色:表示垃圾回收器已经标记为可达了,同时和其关联的对象全部扫描完 就从灰色变成黑色
2.3.1三色标记法执行原理
- 首先,所有对象都是白色
- 从GC ROOT根开始 扫描我的下一级,如果扫描到立马标记成灰色
- 然后继续采用深度优先搜索和广度优先搜索 扫描跟灰色相关联的对象 直到所有灰色对象及其关联的对象全部扫描完毕 灰色变成黑色
- 最终扫描完毕 所有白色对象就是不可达对象 就是可以垃圾回收的对象
3.GC回收算法
3.1标记清除法:
是GC中回收算法最基础的算法,主要用于回收无用的对象 该算法主要分两个阶段:
- 标记阶段:这个阶段 垃圾回收器 从根开始 去进行搜索哪些对象是可达的(可达性分析法) 找到之后把这种对象打一个标记
- 回收(清除)阶段:这个阶段 主要针对于这些没有标记的对象 统一进行回收
3.1.1 缺点
这种回收算法虽然简单 但存在一个非常致命的缺点,会导致内存碎片太多,这样如果后期需要分配连续的空间 很可能会出现内存不足
3.2复制(拷贝)算法:
复制算法 是一种垃圾回收器内存管理技术 一般适用于新生代内存比较多(详情分代算法) 会将内存划分成两个或多个相等的内存空间
-
实现原理:
- 初始状态:所有对象会分配到其中一块内存区域
- 标记阶段:当触发GC时,要标记谁是可达的 表示存活的对象
- 复制阶段:将标记成存活的对象 复制到另一块内存区域
- 原空间清理:前面完成复制后 表示所有对象都已经复制好了 原来的内存空间可以直接被回收
- 角色互换:下一次GC 两块内存区域角色互换 原来的保留内存 变成可用内存
- 晋升阶段:如果经过多次GC依然有对象存活 就会晋升到老年代
-
缺点:
- 内存一分为二 内存利用率减半
- 针对于生成周期比较长的对象,频繁复制会浪费性能
3.3标记压缩(整理)法:
标记压缩法主要包含两个阶段:标记阶段和压缩阶段 来处理内存中的垃圾对象 这样可以完美解决 内存碎片和内存利用率减半的问题
- 标记阶段:类似于标记清除法的标记阶段 也是通过GC ROOT开始 找到哪些对象是存活进行标记
- 压缩阶段:将这些标记存活的对象 进行压缩 移动到内存的一端,使存活的对象紧密的排在一起 压缩阶段结束后其他内存区域就可以进行整体回收
- 缺点:由于每次压缩阶段都需要不断移动存活对象,如果存活对象特别多,或者有一些长期存活的对象 这样会耗费内存性能。
3.4分代算法:
GC会将创建的对象根据回收次数或者对象的大小来划分成不同的区域 主要分为两个区域(第三个区域很少用到不做解释):1.新生代 2.老年代
-
新生代:新创建的对象一般都存放于新生代,新生代还会继续细分为三个区域(Eden区 From区 To区 比例是8:1:1)大部分对象会在这个阶段死亡被回收(适合采用复制算法)
- Eden区:用于存放新建的对象,如果创建的对象比较大时,直接分配到老年代 如果Eden区内存不足 触发GC对新生代进行垃圾回收
- From区:一般是作为上一次GC存活者,下一次GC的扫描者
- To区:一般表示保留内存或者包含一些已经被清理的对象
-
老年代:在新生代经历了一定次数的GC后 依然存活的对象或者创建的对象比较大时 会晋升老年代,而老年代对象相对比较稳定 存活周期很长(更加适合采用标记清除 标记压缩算法)
3.4.1 from和to区之间的转换
- 首先垃圾回收器标记出Eden区和From区中的存活对象,然后将这些存活的对象复制到To区
- GC完成后,原来的From区变成空 因为它存活的对象已经保存到To区了
- 原来的To区现在包含了Eden区和原来的From区存活对象 再将这个原来的To区变成新的From区
- 下一轮GC所有新的对象也会创建在Eden区,然后GC时继续标记Eden区和新的From区 标记好了后 复制到新的To区
3.4.2 新生代和老年代的转换
- 对象在新生代经历一定次数(默认15次),因为每经历一次GC年龄+1,年龄达到15依然存活 晋升老年代
- 新生代中有From区和To区 对象总量超过了一半,那么年龄大于一个阈值也会直接晋升老年代 避免了From区和To区空间变小 出现频繁复制的问题
- 如果对象较大可能直接跳过新生代直接进入老年代
4.面试题
举例
1.什么是GC?
2.GC算法有哪些?--进阶 优缺点
3.GC有哪些标记算法? --优缺点
4.新生代和老年代是什么?如何转换的?