一、思考GC需要完成3件事情
- 哪些内存需要回收?
- 什么时候回收?
- 如何回收?
二、哪些内存需要回收?
Java 内存运行时区域的各个部分,其中程序计数器、虚拟机栈、本地方法栈3个区域随线程而生,随线程而灭;栈中的栈帧随着方法的进入和退出而有条不紊地执行着出栈和入栈操作。这几个区域的内存分配和回收都具备确定性,在这几个区域就不需要考虑内存回收的问题。而Java堆和方法区的内存分配和回收都是动态的,垃圾收集器所关注的是这部分内存。
三、什么时候回收?判断对象是否存活的算法
1. 引用计数算法
给对象添加一个引用计数器,每当有一个地方引用它,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的。但是它很难解决对象之间相互循环引用的问题。
2. 可达性分析算法
基本思路就是通过一系列的称为“GC Roots”的对象作为起点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots 没有任何引用链相连时,则证明此对象是不可用的。
在Java中,可作为GC Roots的对象包括下面几种:
- 虚拟机栈(栈帧中的本地变量表)中引用的对象。
- 方法区中类静态属性引用的对象。
- 方法区中常亮引用的对象。
- 本地方法栈中JNI(即一般说的Native方法)引用的对象。
虽然这些算法可以判定一个对象是否能被回收,但是当满足上述条件时,一个对象并不一定会被回收。当一个对象不可达GC Root时,这个对象并
不会立马被回收,而是出于一个死缓的阶段,若要被真正的回收需要经历两次标记。
如果对象在可达性分析中没有与GC Root的引用链,那么此时就会被第一次标记并且进行一次筛选,筛选的条件是是否有必要执行finalize()方法。当对象没有覆盖finalize()方法或者已被虚拟机调用过,那么就认为是没必要的。
如果该对象有必要执行finalize()方法,那么这个对象将会放在一个称为F-Queue的队列中,虚拟机会触发一个Finalize()线程去执行,此线程是低优先级的,并且虚拟机不会承诺一直等待它运行完,这是因为如果finalize()执行缓慢或者发生了死锁,那么就会造成F-Queue队列一直等待,造成了内存回收系统的崩溃。GC对处于F-Queue中的对象进行第二次被标记,这时,该对象将被移除"即将回收"集合,等待回收。
四、如何回收?垃圾收集算法
1. 标记—清除算法
算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。它的主要不足有两个:一个是效率问题,标记和清除两个过程的效率都不高;另一个是空间问题,标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。
2. 复制算法
为了解决效率问题,一种称为“复制”的收集算法出现了,它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另一块上面,然后再把已使用过的内存空间一次清理掉。这样使得每次都是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,实现简单,运行高效。只是这种算法的代价是将内存缩小为了原来的一半,未免太高了点。
HotSpot 虚拟机默认 Eden 和 Survivor 的大小比例是 8:1。
3. 标记 — 整理算法
标记过程仍然与“标记 — 清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
4. 分代收集算法
一般是把Java 堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。
五、垃圾收集器
1. Serial 收集器
是一个单线程的收集器,在它进行垃圾收集时,必须暂停其它所有的工作线程,直到它收集结束。
2. ParNew 收集器
ParNew 收集器其实就是 Serial 收集器的多线程版本。
3. Parallel Scavenge 收集器
4. Serial Old 收集器
5. Parallel Old 收集器
6. CMS 收集器
7. G1收集器
六、简述 Java 垃圾回收机制
在java中,程序员是不需要显示的去释放一个对象的内存的,而是由虚拟机自行执行。在JVM中,有一个垃圾回收线程,它是低优先级的,在正常情况下是不会执行的,只有在虚拟机空闲或者当前堆内存不足时,才会触发执行,扫描那些没有被任何引用的对象,并将它们添加到要回收的集合中,进行回收。
七、简述java内存分配与回收策率以及Minor GC和Major GC
1. 对象优先在堆的Eden区分配。
2. 大对象直接进入老年代。
3. 长期存活的对象将直接进入老年代。
当Eden区没有足够的空间进行分配时,虚拟机会执行一次Minor GC。Minor GC通常发生在新生代的Eden区,在这个区的对象生存期短,往往发生GC的频率较高,回收速度比较快;Full GC/Major GC 发生在老年代,一般情况下,触发老年代GC的时候不会触发Minor GC,但是通过配置,可以在Full GC之前进行一次Minor GC这样可以加快老年代的回收速度。