1.GC核心思想:对虚拟机可用内存空间,即堆空间中的对象进行识别,如果对象正在被引用,那么称其为存活对象
,反之,如果对象不再被引用,则为垃圾对象,可以回收其占据的空间,用于再分配。垃圾收集算法的选择和垃圾收集系统参数的合理调节直接影响着系统性能。
2. GC roots 来源:
① 虚拟机栈中引用的对象。
② 方法区中类静态属性引用的对象。
③ 方法区中常量引用的对象。
④ 本地方法栈中JNI引用的对象
3. 四种引用对象
① 强引用:不进行垃圾回收
② 软引用:在内存溢出前进行垃圾回收
③ 弱引用:只要有垃圾回收就会回收掉
④ 虚引用:无用对象,垃圾收集时会接收到通知
4. 方法区的垃圾回收
① 废弃常量
② 无用的类
● 该类的所有实例都已经被回收,即Java堆中不存在该类的任何实例。● 加载该类的ClassLoader已经被回收。
● 该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
5. 回收算法
① 复制算法:
复制算法将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。这种算法适用于对象存活率低的场景,比如新生代。这样使得每次都是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况。
② 标记-清除:
标记-清除算法采用从根集合进行扫描,对存活的对象进行标记,标记完毕后,再扫描整个空间中未被标记的对象,进行回收。标记-清除算法不需要进行对象的移动,并且仅对不存活的对象进行处理,在存活对象比较多的情况下极为高效,但由于标记-清除算法直接回收不存活的对象,因此会造成内存碎片。
③ 标记-整理:
标记-整理算法采用标记-清除算法一样的方式进行对象的标记,但在清除时不同,在回收不存活的对象占用的空间后,会将所有的存活对象往左端空闲空间移动,并更新对应的指针。标记-整理算法是在标记-清除算法的基础上,又进行了对象的移动,因此成本更高,但是却解决了内存碎片的问题。该垃圾回收算法适用于对象存活率高的场景(老年代)。
④ 分代收集算法:
● 不同的对象的生命周期(存活情况)是不一样的,而不同生命周期的对象位于堆中不同的区域,因此对堆内存不同区域采用不同的策略进行回收可以提高 JVM 的执行效率。当代商用虚拟机使用的都是分代收集算法:新生代对象存活率低,就采用复制算法;老年代存活率高,就用标记清除算法或者标记整理算法。
● 新生代:
● 老年代:
6. 垃圾收集器
① Serial收集器(复制算法):
新生代单线程收集器,标记和清理都是单线程,优点是简单高效;
② **ParNew收集器 (复制算法): **
新生代收并行集器,实际上是Serial收集器的多线程版本,在多核CPU环境下有着比Serial更好的表现;
③ Parallel Scavenge收集器 (复制算法):
新生代并行收集器,追求高吞吐量,高效利用 CPU。吞吐量 = 用户线程时间/(用户线程时间+GC线程时间),高吞吐量可以高效率的利用CPU时间,尽快完成程序的运算任务,适合后台应用等对交互相应要求不高的场景
④ **Serial Old收集器 (标记-整理算法): **
老年代单线程收集器,Serial收集器的老年代版本
⑤ CMS(Concurrent Mark Sweep)收集器(标记-清除算法):
老年代并行收集器,以获取最短回收停顿时间为目标的收集器,具有高并发、低停顿的特点,追求最短GC回收停顿时间。
⑥ Parallel Old收集器 (标记-整理算法):
老年代并行收集器,吞吐量优先,Parallel Scavenge收集器的老年代版本;
⑦ G1(Garbage First)收集器 (标记-整理算法):
Java堆并行收集器,G1收集器是JDK1.7提供的一个新收集器,G1收集器基于“标记-整理”算法实现,也就是说不会产生内存碎片。此外,G1收集器不同于之前的收集器的一个重要特点是:G1回收的范围是整个Java堆(包括新生代,老年代),而前六种收集器回收的范围仅限于新生代或老年代。