

1)、Mark-Sweep:标记清除
将标记的内存删除、是否对应的内存地址;导致形成零零碎碎的空间,以至于需要大空间对象时分配失败

2)、Copying:拷贝
分配几个大空间,根据根可达算法找出可用的数据放入到另一个大空间中,再次删除要回收的对应大空间
缺点:浪费空间

3)、Mark-Compact:标记压缩
回收的时候顺带将可用的进行重排序
缺点:效率低,比copy还低

Java1.8默认都是把内存分为两大年代,回收一般使用分带回收机制;即分为新生代与老年代
新生代使用copying(拷贝算法),老年代使用Mark Compact(标记压缩算法)
新生代与老年代在内存比例为1:3,而新生代中eden与survivor比例是8:1:1
1)、新生代使用copying(拷贝算法)
新生代第一次垃圾回收(major gc)将伊甸区(eden)中存活的数据拷贝到幸存区(survivor-0)之后将eden区删除回收;
第二次将伊甸区(eden)中存活的对象与(survivor-0)幸存区0中对象都拷贝到幸存区1(survivor-1)中 将对应的eden与survivor-0都回收;
第三次就又将survivor-1拷贝回survivor-0中,回收eden与survivor-0区;
循环上面三个步骤;当存活的对象达到回收计数阈值时将对应的对象移到老年代中
2)、老年代使用Mark Compact(标记压缩算法)或者Mark Sweep(标记清除算法)结合使用
当老年代达到设置的阈值时就会触发full gc

垃圾回收器是随着内存的不断增长而演进的

即年轻代使用serial,老年代使用serial old垃圾收集器回收
即年轻代使用Parallel Scavenge,老年代使用Parallel Old垃圾回收器

工作线程与垃圾回收线程同时操作会存在误认为某对象可以进行垃圾回收,需要三色标记算法解决:
黑色标记:满足自己已经标记、已经自己指向的对象也都标记(孩子)则为黑色
灰色标记:自己标记完成,还没来得及标记指向的对象则标记为灰色
白色标记:还没有遍历到的节点

当上图B->D,没有扫描到,业务逻辑实现A->D产生了,则会将D当成垃圾,CMS解决方案就是将A标记为灰色,依然会漏标(不建议使用CMS)

主要为分区算法,将部分回收并发收集,压缩空闲空间不会延长GC的暂停时间,更容易预测GC暂停时间,使用于不需要很高吞吐量的场景;G1主要是物理不分代(一个个小区域),逻辑分带

使用分页算法(go lang回收算法),ZGC的核心算法为颜色指针,也是进行分区,但是不再进行新生代与老年代是分带,

7)、Shenandoah,红帽提供开源的垃圾回收器
jstat -gc(参数) + 进程号 : 跟踪gc的一些信息
jstat -gc(参数) + 进程号 + 刷新毫秒数 :跟踪gc的一些信息以多少毫秒刷新一次
当存在cpu内存飙升时可以使用:
top :查看那个进程使用cpu很高
top -hp + 进程号 : 查看那个线程使用cpu很高
最后使用jstack 查看对应的栈信息看那个方法出现问题
jmap histo + 进程号 :生成对象图
jmap histo + 进程号 | head 20 : 生成对象图中最大的前20个类对象所占比重
使用jmap有一个严重的问题:当将堆转存文件时,会卡死状态,直到转存成功再运行(生产环境不建议使 用)
arthas阿里开源的jvm诊断工具,涵盖上面命令,主要有:
1、dashboard : 仪表盘,查看那个线程占用支援比较多
2、head dump: 堆转储文件
3、thread :列除所有线程,看那个cpu吃线程比较多
thread -d : 查看是否存在死锁
4、jvm : 列出java中设置的jvm参数,以及使用了哪些垃圾回收器
5、jad : 反编译java代码
6、redefine : 在线修改class
7、trace :单机版链路追踪,分布式链路追踪使用(zipkin)