目录
1. 什么是垃圾?
没有引用指向的对象就是垃圾
2. 如何回收垃圾?
1. reference count: 引用计数,不能回收环状引用的垃圾
2. Root Searching:根可达算法,首先找到根对象,然后顺着找到其他有用的对象。Which instances are roots?
- JVM stack(线程栈变量):即main线程栈中的方法可以访问到的对象
- native method stack(JNI指针):本地方法用到的本地变量
- run-time constant pool(常量池):方法区中的常量
- static references in method area(静态变量)
JVM虚拟机不采用引用计数法,只通过可达性分析进行垃圾回收
3. GC Algorithms 常见的垃圾回收算法
- Mark-Sweep(标记清除):标出来,清除掉。两遍扫描,第一边标记有用的,第二遍清除没标记的,执行效率偏低,容易产生碎片
- Copying(拷贝):内存一分为二,把有用的拷贝到另一个区域,清除掉原区域。适用于存活对象较少的情况,只扫描一次,效率提高没有碎片,但是浪费空间,移动复制对象,需要调整对象的引用
- Mark-Compact(标记压缩):清理的时候同时压缩到前面的内存中,空间连续没有碎片。扫描两遍,移动对象,第一遍扫描出有用的对象,第二遍便清除边移动,效率低很多
4. 堆内存逻辑分区
不适合不分代垃圾收集器
分代算法和垃圾回收器有关,分代是存在于ZGC之前的所有垃圾回收器,G1是逻辑分代物理不分代,其他的使用分代算法的垃圾回收器是逻辑物理都分代
部分垃圾回收器使用的模型
- 除了Epsilon、ZGC、Shenandoah之外的GC都是用逻辑分代模型
- G1是逻辑分代,物理不分代
- 其他的是逻辑分代,物理分代
1. 新生代(young)
使用Copying算法
- eden:默认比例8,刚new的对象
- (from/to)survivor(s0/s1):默认比例1,回收一次后没被干掉的
- (to/from)survivor(s1/s0):默认比例1
2. 老年代(old、tenured(终身))
多次GC没干掉的移动到老年代,使用Mark Compact 或 Mark Sweep算法
3. 一个对象从出生到消亡的过程
- 对象产生在栈上分配,分配不下就进行大小判断,如果特别大就直接进入old区,如果不够大就进入TLAB(eden)
- eden第一次GC后进入s0
- s0 经过一次GC后进入s1,同时eden中的某些对象也跟着进入to survivor
- s1区的对象年龄够了之后会进入old区
- 可以通过:-XX:MaxTenuringThreshold 设置进入old区的年龄限制
- 如不指定,默认为如下:
- Parallel Scavenge:15 (mark word中对象分代年龄只有4bit,最大就是15)
- CMS:6
- G1: 15
动态年龄
- s0 -> s1超过50%,两个survivor区之间互相拷贝(eden区的也可能被拷贝进来),只要超过了50%就把年龄最大的直接放入old,没有了最大年龄的限制
- -XX:TargetSurvivorRatio 指定上述的目标存活率,默认为50%
4. 栈上分配和线程本地分配
1. 什么样的对象可以在栈上分配?
- 线程私有小对象:小对象,线程是私有的
- 无逃逸:只在某一段代码中使用,出了这段代码就不能认出它了
- 无需调整
- 支持标量替换:可以使用普通的属性代替对象,比如下面这个类
class User {
int id;
String name;
public User(int id, String name){
this.id = id;
this.name = name;
}
}
栈上分配比堆上分配块,栈上分配不下了,会优先本地分配
2. 线程本地分配TLAB(Thread Local Allocation Buffer)
在eden区分配对象的时候,线程会进行空间的征用,多个线程需要争抢,多线程同步的场景下,效率就会降低,所以出现了TLAB机制
- 占用eden,默认1%:在eden取1%的空间作为该线程独有,分配对象的时候现往线程独有的这块空间分配
- 多线程时不用竞争eden就可以申请空间,提高了效率
5. GC
1. 一些概念
-Xms(起始堆大小)/-Xmx(最大堆大小)
-Xmn
- eden
- s0
- s1
old/tenured
X是分标参数,-开头是标志参数,-X开头是非标参数,-XX是不稳定参数,m是memory,s是最小值,x是最大值,n是new
MinorGC/YGC:年轻代空间耗尽时触发
MajorGC/FullGC:老年代无法继续分配空间时触发,新生代老年代同时回收
2. GC何时被触发?
- Eden空间不足 -> YGC
- Old空间不足或调用System.gc() -> FGC