-
仍处于存活状态中的线程对象。
-
Native 方法中 JNI 引用的对象。
什么时候回收
==============
不同的虚拟机实现有着不同的 GC 实现机制,但是一般情况下每一种 GC 实现都会在以下两种情况下触发垃圾回收。
-
Allocation Failure:在堆内存中分配时,如果因为可用剩余空间不足导致对象内存分配失败,这时系统会触发一次 GC。
-
System.gc():在应用层,Java 开发工程师可以主动调用此 API 来请求一次 GC。
如何回收垃圾
==============
由于垃圾收集算法的实现涉及大量的程序细节,各家虚拟机厂商对其实现细节各不相同,因此本课时并不会过多的讨论算法的实现,只是介绍几种算法的思想以及优缺点。
标记清除算法(Mark and Sweep GC)
从"GC Roots"集合开始,将内存整个遍历一次,保留所有可以被 GC Roots 直接或间接引用到的对象,而剩下的对象都当作垃圾对待并回收,过程分两步。
-
Mark 标记阶段:找到内存中的所有 GC Root 对象,只要是和 GC Root 对象直接或者间接相连则标记为灰色(也就是存活对象),否则标记为黑色(也就是垃圾对象)。
-
Sweep 清除阶段:当遍历完所有的 GC Root 之后,则将标记为垃圾的对象直接清除。
如下图所示:
-
优点:实现简单,不需要将对象进行移动。
-
缺点:这个算法需要中断进程内其他组件的执行(stop the world),并且可能产生内存碎片,提高了垃圾回收的频率。
复制算法(Copying)
将现有的内存空间分为两快,每次只使用其中一块,在垃圾回收时将正在使用的内存中的存活对象复制到未被使用的内存块中。之后,清除正在使用的内存块中的所有对象,交换两个内存的角色,完成垃圾回收。
-
1.复制算法之前,内存分为 A/B 两块,并且当前只使用内存 A,内存的状况如下图。
-
2.标记完之后,所有可达对象都被按次序复制到内存 B 中,并设置 B 为当前使用中的内存。内存状况如下图。
-
优点:按顺序分配内存即可,实现简单、运行高效,不用考虑内存碎片。