GC
垃圾回收算法
- 标记-清理
标记、清理;会产生不连续碎片
- 标记-复制
将内存分为两部分
标记、复制存活对象到另一部分,清空垃圾部分
- 标记-整理
标记、移动存活的对象,到内存的一段
清理掉边界外的空间
- 分代算法
对不同的内存区域,使用上述不同的回收算法
- 新生代内存 采用复制算法
原因: 新生代垃圾回收时,对象死亡率高,则仅复制少数存活对象即可
- 老年代 采用 标记-清除 || 标记-整理算法
原因: 老年代垃圾回收时,对象死亡率低,仅清除少量死亡对象即可
对象的分配
● 对象优先在eden区 分配
对象优先在eden区分配,
eden区没有足够空间时,触发 Minor GC
虚拟机发起 【Minor GC】 = {
情况1 : eden 已使用内存 < suvivor内存
eden 内对象 转移到 suvivor内存
情况2 : eden 已使用内存 > suvivor内存
eden 内对象 转移到 老年代
}
FULL GC 触发条件 = {
新生代对象总空间 > 老年代剩余连续空间
Minor GC 平均晋升空间大小 > 老年代连续剩余空间,则触发FULL GC
}
大对象进入老年代
避免 剩余较多内存空间 时,直接触发GC
长期存活对象进入老年代
对象在Eden出生, 每经历一次minor GC 并被移动到survivor区,则age++
年龄增加到一定程度(15岁),则进入老年代。
此外 当suvivor区中一般以上对象年龄相同,则>=该年龄的对象进入老年代。
判断对象死亡 的方法
- 引用计数法
每当对象被引用,则计数器++;
每当引用失效,则计数器–;
计数器值=0时,标记对象可回收
【存在问题】 : 两个对象相互引用,则无法被回收
- 可达分析算法
从GC roots对象 向下搜索,如果没有路径到达目标对象。则标记目标对象可回收。
GC roots 对象:
- 虚拟栈中 引用对象
- 方法区 静态属性的引用对象
- 方法区 常量引用的对象
- 二次标记
标记可回收的对象,并非立刻回收。他们加入一个队列中进行二次标记。如果在二次标记前,对象产生引用则不会被回收。
垃圾收集器:
1、CMS
四个阶段:初始标记、并发标记、重新标记、并发回收
缺点:
- 【cpu资源敏感】 : 并发期间,GC程序占用CPU资源,导致用户程序吞吐量低。
- 【无法处理浮动垃圾】 : 并发清除 阶段,GC和用户程序并发,在该阶段仍会产生垃圾。这些垃圾仅能在下一次GC中回收。
- 【标记-清除】算法,造成 大量【不连续】空间碎片
2、G1
特点:
提供规整的内存
可预测的停顿,能够控制回收时间在 N 毫秒内
以 Region 为单位,适合大内存的服务器
使用额外的空间来保存对象的引用关系,会占用额外的空间,内存碎片少
关键字
逻辑上仍然有新生代、存活代、老年代,但物理上是以 region 为单位的
在新生代:Yong GC 模式
在老年代:Mixed GC 模式 https://blog.csdn.net/m0_63437643/article/details/122601042
三色标记:(对对象进行可达性分析)
- 黑色:已被检查,对象成员也被检查了
- 灰色:被检查了,但是对象成员还未被全部检查
- 白色:对象还未被检查(若全部检查结束后,还是白色,则表明是不可达对象)
Region 组成
- 每个 region 1-32M (2 的 n 次幂大小)
- 伊甸园、新生代、老年代
- Humongous 区:用来存放大对象(超过了 region 的一半大小)
Card Table 卡表
RSet:hash 表
- key:引用本 region 内对象的其他 region 起始地址
- value:被引用的对象在 card table 中的索引位置
作用:解决跨代引用的问题
CollectionSet
gc 过程
五个阶段:
初始标记(STW)、根Region扫描、并发标记、重新标记、并发回收(STW)
YGC:
MixedGC:两大步骤
- 全局并发标记
- 拷贝存活对象
对象丢失问题:
并发标记过程中,动态对象没有被标记,因为被误认为是垃圾对象而回收
解决:
1、增量更新:CMS使用
2、STAB:G1 使用
再加上写屏障捕获对象修改
3、ZGC
特点
- 全程并发
- 超低的停顿时间(10ms)
- 暂时没有分代的概念
- 仅支持64位系统(因为要用64位的指针)
组成
- Page
分三种类型:小型、中型、大型
容量分别是 2M、32M、存放 4M 以上大对象的不固定大小容量
- 染色指针
让指针存储额外的信息
linux 只使用前 46 位(linux 只支持 64T 的内存)
表示当前对象处于 ZGC 的哪个阶段
更细颗粒度的停顿(不用STW,而是用读屏障)
指针关键字:
finalizable、remapped、marked1、marked0
NUMA(非统一内存访问)
空间(虚拟内存)换时间
GC 步骤
-
初始标记
-
并发标记
-
重新标记
-
并发预备重分配
主要是处理软引用、弱引用、虚引用,重置 Page 的 Forwarding Table,收集待回收的 Page 信息到 Relocation Set 里
-
初始迁移
-
并发迁移
-
并发重映射
缺点:
单代吞吐量降低
会出现分配停顿的现象
并发GC,会导致CPU偏高
内存泄露的例子
- 单例模式
对象长时间不使用,但是一直不释放
2. 容器内数据无用,但长时间不释放
参考:
- https://juejin.cn/post/7216967809158299703#heading-11
- https://www.infoq.cn/article/3wyretkqrhivtw4frmr3
- https://ata.atatech.org/articles/12020228482?spm=ata.23639746.0.0.412218baqi4KiS
- https://cr.openjdk.org/~pliden/slides/ZGC-OracleDevLive-2020.pdf?spm=ata.21736010.0.0.781310ceXcXP5Y&file=ZGC-OracleDevLive-2020.pdf
- https://ata.atatech.org/articles/11000199497?spm=ata.23639746.0.0.412218baqi4KiS