JVM 学习
如何判断一个对象是否是垃圾
-
引用计数法
如果有一个对象指向这个对象计数+1
取消一个引用对象技术-1
若减为0则回收
无法解决循环引用
-
根可达算法(JVM使用的方法)
main函数启动的时候会产生一个GC Root 每个对象若可达root则不是垃圾,否则将被是为垃圾
Root包括:
- JVM stack
- native method stack
- runtime constant pool
- static references in method area
- Clazz
JVM 垃圾回收算法
-
Mark-Sweep(标记清除)
将垃圾标记后清除(会有许多碎片化的内存区域)
-
copying(拷贝)
有两个内存区域,将一个区域有用的对象拷贝到另个区域(消耗内存)
-
Mark-Compact(标记压缩)
将碎片整理好(消耗CPU)
JVM 垃圾回收器
分代:
分代模型分为新生代,老年代
绝大多数对象在新生代回收掉
新生代(Copy垃圾回收算法):
-
8: eden
-
1:survivor *2
这两个区域会不停的复制,每复制一次都会进行将对象的年龄放入老年代
若这两个区域满了会将对象直接放入老年代
老年代(Mark Compact):
- tenured
PS: 对象在创建的时候若对象不大则在栈中创建,若太大则直接放入垃圾回收器。
若对象放入不了YGC放入老年代,若能在YGC放入则放入YGC。
在YGC中,没被回收对象经过路线,eden->survivor1 ->eden->survivo1 ->survivor 2->survivo1
之后就在surivivor1和survivo2中往返若年龄符合老年代标准放入老年代。
在这之中被回收对象在GC中的生命周期结束
打印所有可调参数: java -XX:+PringCommandLineFlags
分代回收器:
- Young:
Serial
ParNew
Parallel Scavencge
- Old:
CMS
Serial Old
Parallel Old
不分代回收器:
G1
ZGC
垃圾回收
Serial: 每过一段时间所有线程停止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采取逻辑分代物理不分代
G1同样使用三色标记法,
与CMS不同的是G1采取的是:SATB (Snapshot At the Begining)[写屏障]
G1与CMS的不同做法是在标记的时候,将对象放入一个队列中去。
之后remark只扫描队列中的对象
JVM 线上问题解决
jps
列出Java进程
jinfo
jvm 基本信息
jstak 进程号
jvm进程上运行的线程状态
这个命令可以用来定位死锁
jstat -gc 进程号
统计gc的信息
jmap -histo 进程号
定位哪些对象在吃内存 注意,这个命令会引起系统卡顿(线上不能用)
jmap -dump:format=b,file=xxx.hprof 进程号
将堆存成一个文件
之后我们可以使用一些工具来分析这些堆内存,例如:
- mat
- jprofiler
- jhat
- jvisualvm
jvm自带图形化工具
jdk安装目录的bin目录
- jvisualvm
- jconsole
arthas
阿里开源的工具
arthas
dashboard
用字符界面模拟的图形界面jvm
把jvm的所有信息输出thread
把所有线程所列出来thread -b
查看死锁heapdump
相当于jmapjad 类名
将java源码反编译redefine class路径
将文件热更新到线上去
排查
-
jvm突然升高
- 使用arthas查看CPU占用最高的线程
- 若是业务线程则表示有大量计算操作
- 若是JVM线程则表示有频繁的FGC