垃圾判断
引用计数算法
给对象加一个引用计数器,有一个地方引用时就+1,引用释放就-1,为0时代表可回收。但是因为无法解决循环引用问题,java虚拟机并没有采用这种方式。
可达性分析算法
通过GC Root对象作为起点,根据对象引用关系,向下搜索,所走过的路径称为引用链,当一个对象到GC Root没有任何引用链相连,证明对象是可回收的。
可作为GC Root的对象:
- 虚拟机栈(栈帧中的本地变量表)中引用的对象
- 方法区中类静态属性引用的对象
- 方法区中常量引用的对象
- 本地方法栈中 JNI(即一般说的 Native 方法) 引用的对象
在判断时对于引用也做了明确的分类:
- 强引用:类似于 Object obj = new Object(); 创建的,垃圾收集器永远不会回收掉被强引用的对象。
- 软引用:SoftReference 类实现软引用。在系统要发生内存溢出异常之前,将会把这些对象列进回收范围之中进行二次回收。
- WeakReference 类实现弱引用。对象只能生存到下一次垃圾收集之前。在垃圾收集器工作时,无论内存是否足够都会回收掉只被弱引用关联的对象。
- PhantomReference 类实现虚引用。无法通过虚引用决定一个对象的生存时间,唯一目的就是能在这个对象被收集器回收时收到一个系统通知。
垃圾回收
标记清除算法
两步:标记+清除。缺点:效率不高,会产生大量内存碎片,当后面要存储大对象时,如果没有连续的内存空间来存放,就需要扩容或抛出内存溢出的异常。
复制算法
将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当一块内存用完了,就将还存活着的对象复制到另外一块上,然后清理掉前一块。
标记整理算法
标记过程与标记清除算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
分代收集算法
HotSpot 虚拟机采用的就是分代收集算法。
根据对象存活周期的不同,将内存划分为几块,根据年代的特点来选择最佳的收集算法。当有新的对象创建时,首先使用新生代的初始区(Eden区)和from幸存区(Survivor from),经过一次Young GC后,还存活的对象会通过GC的复制算法移动到to幸存区(Survivor to)(有可能遇到to幸存区没有足够空间存放剩余的存活对象,则将通过分配担保机制筛选出符合一定条件的对象直接进入老年代),然后清理掉初始区和from幸存区,此时在to幸存区的对象年龄+1,当年龄到达某个值时(默认15),会移动到老年代;清理老年代中的对象使用Full GC,采用的标记清除和标记整理算法。