GC如何判断对象可以被回收
引用计数法(已被淘汰的算法)无法解决循环引用问题
每一个对象有一个引用属性,新增一个引用时加一,引用释放时减一,计数为0的时候可以回收。
根可达算法
从GcRoot开始向下搜索,搜索所走过的路径被称为引用链,当一个对象到GcRoot没有任何引用链相连时,则证明此对象是不可用的,那么虚拟机就可以判定回收。
GcRoot是什么
虚拟机栈中引用的对象
方法区中静态属性引用的对象
方法区中常量引用的对象
本地方法栈中(即一般说的native方法)引用的对象
如何回收内存对象,有哪些回收算法?
1.标记-清除(Mark-Sweep)算法
2.复制算法
3.标记-整理算法
从最开始,到1.8都是将堆内存分为两个大的年代,新生代老年代,
刚刚诞生的对象存在于新生代,进行多次YGC没有清除的对象存在老年代,根据不同年代采取不同的算法,分代算法。
新生代(YGC)分为Eden区,survivor1,survivor2,采用复制算法;根据统计,经过一次垃圾回收的对象为90%,为了避免空间的浪费,默认比例为8:1:1
老年代(FGC) 采用标记清除或者标记整理,或者两者联合使用,多次标记清除后进行一次标记整理。
垃圾回收器
随着内存大小的不断增长而演进。
几兆 - 几十兆
Serial:单线程STW垃圾回收 年轻代
Serial old:单线程回收 老年代
几十兆 - 上百兆 1G (ps + po)1.8默认
Parallel Scavenge 多线程的STW垃圾回收 年轻代
Parallel Old 多线程的STW回收 老年代
几十G(Concurrent GC)
ParNew
CMS
其他几个回收器:
Epsilon(1.开发JVM的人Debug使用2.内存超大,不担心内存问题,不需要任何处理)只扫描不清除
G1 摒弃分代模型,采用分区模型(随着内存的增大,年轻代,老年代的GC时间增长)(区大小:1,2,4,8,16,32M)
一次YGC回收需要把年轻代全部回收,时间较长 (物理上不分代,逻辑上分代。)
ZGC(Oracle) 分页算法,核心是颜色指针,100ms内进行一次回收
shenandoah(ReadHat)与ZGC类似
三色标记算法:黑色不会再被扫描,从灰色向下扫描;
在CMS并发标记阶段(三色标记算法)中会出现两种情况:
浮动垃圾(下次再扫描一次即可)
漏标问题
阶段一
解决方案:将A变为灰色
阶段二:在标为灰色时,未来得及扫描D,A被线程1再次改为黑色。那么D永远扫不到。
解决方案:
重新标记(remark阶段),必须重新从头扫描一遍,STW时间很长(因为内存很大)。。。
三色标记在哪?
三色标记(01,10,11)在对象头(MarkWord),mw包含三个信息,第一类锁信息,第二类HashCode,第三类GC
G1图示
熟悉GC常用算法,熟悉常见垃圾收集器,具有实际JVM调优实战经验
调优
jmap -histo 16368 head -20 : 查看进程运行占用内存最多的对象 jmap会让堆内存暂停,生产不使用
Arthas的使用
dashboard :概览程序的 线程、内存、GC、运行环境信息
jvm:查看jvm的信息,以及所使用的GC算法等