
当我们发现,对象均没有任何来自栈的引用,那么这个对象就可以被回收了。
objects on the heap are no longer needed when they don’t have a connection to the stack.
- Person p1 = new Person(); // 1
- Person p2 = new Person(); // 2
- Person p3 = new Person(); // 3
- List
personList = Arrays.asList(p1, p2, p3); // 4 - p1 = null; // 5
- personList = null; // 6
在4执行完成后,我们的内存空间大概是这样的:

可以看到,三个Person对象被三个Person变量引用的同时,被一个List也在引用
当执行5时,P1指向的引用会被释放吗?不会。

因为这个对象除了被p1直接引用外,还被persons的List间接引用,因此尚不可回收。
当执行至6时,这个对象可以被回收了吗?可以的。

此时不再有栈上的变量指向它,因此可以回收。(LIst Object也可以被回收了)
将继续引用的对象标记为1,不再引用的对象保持为0,这样就可以回收标记是0的对象了。
例如,在上面的例子中:
- Person p1 = new Person(); // 1
- Person p2 = new Person(); // 2
- Person p3 = new Person(); // 3
- List
personList = Arrays.asList(p1, p2, p3); // 4 - p1 = null; // 5
初始还没有开始标记时,几个标志位置均为0

开始标记后,

1. stop the world
在标记的过程中,很可能还会被重新引用,或者产生新的对象,很容易和标记线程发生冲突,因此,stop the world简单粗暴,将暂停应用内的线程,开始正式标记工作。
2. 引用计数法
在对象上面维护一个引用计数器,每有一个引用指向自己,计数器+1,每有一个引用不再指向自己,计数器-1,垃圾回收那些计数器为0的对象。
看起来引用计数法不会stop the world,但是,可能会因为循环引用导致内存泄漏,无法回收。
- class Nest {
-
- private Nest;
-
- public Nest getNest() {
- return nest;
- }
-
- public void setNest(Nest nest) {
- this.nest = nest;
- }
-
- }
- public class IslandOfIsolation {
-
- public static void main(String[] args) {
- Nest n1 = new Nest(); // 1
- Nest n2 = new Nest(); // 2
-
- n1.setNest(n2); // 3
- n2.setNest(n1); // 4
-
- n1 = null; // 5
- n2 = null; // 6
- }
-
- }
我们发现,执行完4步骤,在n1和n2之间互相引用了彼此,各自计数为2

执行完步骤6,此时计数仍不为0,因为n1和n2之间互相引用了彼此

但是,这两个对象实际上跟栈已经没有关联了,应该被回收。所以引用计数法无法解决循环引用的问题。
常规清除法
常规清除法就直接把没有标记的对象直接清掉,不做其他处理,这会带来的问题是,内存碎片化

删除后,会空出内存位置,可以在空的位置继续创建对象,但是,来个占用内存较大的对象可能就没法创建了。

清除整理法
清除整理法是两个步骤:
第一个步骤与常规清除的办法一致,直接删除未标记的对象。
第二个步骤,将对象移动内存位置,将间隙填满,解决碎片化的问题。

复制清除法
将标记的对象复制到另外一个内存区域,然后清除当前的整个内存区域

然后清除上面整个内存空间

| 类型 | 详情 | 适用场景 |
| Serial GC | 采用单线程、Stop the World的方式进行垃圾回收,对于新生代采用标记-复制法,对于老年代采用的是标记-整理法。 | 适用于小型应用 |
| Parallel GC | 采用多线程、Stop the World的方式进行垃圾回收,对于新生代采用标记-复制法,对于老年代采用的是标记-整理法。 | jdk 1.8 默认模式 |
| CMS GC | Concurrent Mark Sweep Garbage Collect 采用Stop the World 的方式回收新生代,标记-复制法。 两次Stop the World的方式回收老年代,标记-清除法。尽可能与应用程序并行执行,如果内存极度不足则暂停应用的线程。 | |
| G1 GC | 将内存划分为多个更小的区域,在其内部追踪可达对象和可回收对象,在小区域之间进行复制,可以在复制的同时实现内存整理。依然会Stop the World,但是时间更短。 | |
| Z GC | 在回收的过程中,会采用引用重新映射的方式解决碎片化的问题。stop the world时间很短。 | 自java15开始,仅支持64位系统 |
内存分配速率:在内存中创建对象的速率。
堆的体量:堆中存活的对象个数和大小。
更新速率:对象更新的速率。
平均存活时间:对象平均存活时间,有的在内存中很快释放,有的需要存储很久。