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 常见的垃圾回收算法

  1. Mark-Sweep(标记清除):标出来,清除掉。两遍扫描,第一边标记有用的,第二遍清除没标记的,执行效率偏低,容易产生碎片

在这里插入图片描述

  1. Copying(拷贝):内存一分为二,把有用的拷贝到另一个区域,清除掉原区域。适用于存活对象较少的情况,只扫描一次,效率提高没有碎片,但是浪费空间,移动复制对象,需要调整对象的引用

在这里插入图片描述

  1. 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. 一个对象从出生到消亡的过程
  1. 对象产生在栈上分配,分配不下就进行大小判断,如果特别大就直接进入old区,如果不够大就进入TLAB(eden)
  2. eden第一次GC后进入s0
  3. s0 经过一次GC后进入s1,同时eden中的某些对象也跟着进入to survivor
  4. 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何时被触发?
  1. Eden空间不足 -> YGC
  2. Old空间不足或调用System.gc() -> FGC
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐