回收方式
引用计数法:给堆中的每个对象记录一个引用个数,引用个数等于0就认为是垃圾,但这种方式无法解决循环引用的问题,java早期使用的垃圾回收使用此种方式。
根可达算法:这种方式是在内存中,从根对象一直往下查找,找不到的对象就是垃圾。
哪些是根对象:Stack->JVM Stack、Native Stack、Class类、run-time constant pool常量池、static referance静态变量
回收算法
MarkSweep标记清除算法
先标记垃圾再清除垃圾,此算法简单,但会造成内存碎片
Copying拷贝算法
拷贝算法将内存分成大小相同的两份,当清理时将存活的对象拷贝到另一块空间,该算法解决了内存碎片问题,但造成了空间的浪费,同时回收的效率会受到存活对象多少的影响。
MarkCompact标记压缩算法
这种算法在标记阶段与标记清理算法一致,但标记完成之后不会直接清理,而是将存活对象往一边移动,然后将边界以外的内存直接清除。
JVM有哪些垃圾回收器
STW:在垃圾回收过程中,java的所有用户线程都是停止的,GC线程除外,本地方法可以执行,但是它们不能与JVM交互。各种GC回收的调优在于减少STW的时间
分代算法
年轻化:Serial、ParallelNew、
老年化:CMS、Serial Old、ParallelOld
Serial串行:简单,用于几十M的内存空间
CMS:Comcurrent Mark Sweep并行标记清理算法:让一部分线程与GC一起进行。初始标记(STW)--并发标记--重新标记(STW)--并发清除
初始标记:标记根对象直接引用的对象
并发标记:继续标记其它对象,与用户线程并发执行
重新标记:对并发标记过程中变化的对象进行重新标记
并发清除:将产生的垃圾进行清除
在清除过程中,用户线程还会产生新的垃圾,因此产生了浮动垃圾,这些浮动垃圾只能下次再清除了。
G1:将内存分成多个Region,不再区分新生代与老年代,它的内存模型是实际不分代,但逻辑上还是区分的。GC分为4个阶段
初始阶段:标记出GC Root直接引用的对象,STW
标记Region:通过RSet标记出上一个阶段标记的Region引用到的Old区的Region ,并发的
并发标记:跟CMS相似,不遍历所有Old区的对象,只遍历第二步标记出来的Region
重新标记:过程与CMS相似
垃圾清理:与CMS相似,G1采用拷贝算法,直接将Region对象拷贝到另一个Region,但只查垃圾比较多的对象对待清理。
CMS的算法就是三色标记
黑色:自己与成员对象都标记完成
灰色:自己标记完成,成员对象未标记
白色:自己未标记完成
CMS通过increament update的方式来解决漏标的问题。
G1中使用SATB(Snapshot at the beginning)方式解决漏标记的问题
RoketMq 的broker使用G1垃圾回收器
JVM调优
参数分三类:
标准指令,以-开头
-version 在java的bin目录下输入java -help查看
非标准指令:以-X开头,与特定的JAVA虚拟机hotspot相关,在java的bin目录下输入java -X查看这类参数有哪些
不稳定参数:
java -XX:+PrintFlagsInitial查看默认的不稳定参数
java -XX:+PrintCommandLineFlags 查看当前命令的不稳定指令
java -XX:+PrintFlagsFinal:查看所有不稳定参数中实际生效的值