引用计数法
如果有一个对象指向这个对象计数+1
取消一个引用对象技术-1
若减为0则回收
无法解决循环引用
根可达算法(JVM使用的方法)
main函数启动的时候会产生一个GC Root 每个对象若可达root则不是垃圾,否则将被是为垃圾
Root包括:
- JVM stack
- native method stack
- runtime constant pool
- static references in method area
- Clazz
Mark-Sweep(标记清除)
将垃圾标记后清除(会有许多碎片化的内存区域)
copying(拷贝)
有两个内存区域,将一个区域有用的对象拷贝到另个区域(消耗内存)
Mark-Compact(标记压缩)
将碎片整理好(消耗CPU)
分代:
分代模型分为新生代,老年代
绝大多数对象在新生代回收掉
新生代(Copy垃圾回收算法):
8: eden
1:survivor *2
这两个区域会不停的复制,每复制一次都会进行将对象的年龄放入老年代
若这两个区域满了会将对象直接放入老年代
老年代(Mark Compact):
PS: 对象在创建的时候若对象不大则在栈中创建,若太大则直接放入垃圾回收器。
若对象放入不了YGC放入老年代,若能在YGC放入则放入YGC。
在YGC中,没被回收对象经过路线,eden->survivor1 ->eden->survivo1 ->survivor 2->survivo1
之后就在surivivor1和survivo2中往返若年龄符合老年代标准放入老年代。
在这之中被回收对象在GC中的生命周期结束
打印所有可调参数: java -XX:+PringCommandLineFlags
Serial  ParNew Parallel ScavencgeCMS Serial Old Parallel OldG1  ZGCSerial: 每过一段时间所有线程停止STW(stop the world) 单个线程垃圾回收线程进行垃圾回收
Parallel Scavencge:根serial一样,只不过使用多个线程进行垃圾回收
ParNew:它根Parallel Scavencge差不多,它只是配合CMS一起使用的
在CMS并发标记的时候,当一个被标记了,工作线程中又出现了对象引用它,这种称为错标。
CMS的解决方法是重新标记,这里采用的算法为三色标记法(黑,白,灰)
白色:未被标记的对象
灰色:自身被标记,成员变量没被标记
黑色:自生被标记,成员变量均被标记
错标产生情况:
假如 A 指向 B , B 指向 C [A->B->C]
A(黑色) 自己已经被标记,成员变量也标记完了。
B(灰色) 自己被标记完了,C没被标记
C(白色) 没有被标记
这时候 B->C 消失变为 A->C
这时候垃圾回收器会将C 给回收。
错标解决办法:
将A 重新标记为灰色,垃圾回收器重新进行标记,这时是又STW的
漏标产生情况:
A 的 第一个属性被标记了,第二个属性正在标记中第一个属性引用了C
当第二个属性标完后,整体为黑色,但是C对象仍然是白色的,最终C漏标了
CMS 在内存大的时候,remark 标记阶段的时间仍然很长。
G1采取逻辑分代物理不分代
G1同样使用三色标记法,
与CMS不同的是G1采取的是:SATB (Snapshot At the Begining)[写屏障]
G1与CMS的不同做法是在标记的时候,将对象放入一个队列中去。
之后remark只扫描队列中的对象
列出Java进程
jvm 基本信息
jvm进程上运行的线程状态
这个命令可以用来定位死锁
统计gc的信息
定位哪些对象在吃内存 注意,这个命令会引起系统卡顿(线上不能用)
jmap -dump:format=b,file=xxx.hprof 进程号 将堆存成一个文件
之后我们可以使用一些工具来分析这些堆内存,例如:
jdk安装目录的bin目录
阿里开源的工具
arthas
dashboard  用字符界面模拟的图形界面jvm 把jvm的所有信息输出thread 把所有线程所列出来thread -b 查看死锁heapdump 相当于jmapjad 类名 将java源码反编译redefine  class路径  将文件热更新到线上去jvm突然升高
- 使用arthas查看CPU占用最高的线程
- 若是业务线程则表示有大量计算操作
- 若是JVM线程则表示有频繁的FGC
原文:https://www.cnblogs.com/bananafish/p/13341904.html