1 概述
哪些内存需要回收?
什么时候回收?
如何回收?
Java垃圾回收主要关注的是堆和方法区。
2 Java如何判断对象存活?
有种算法是引用计数算法,给每一个对象添加一个引用计数器,每当有一个地方引用他,计数器值+1,引用失效时,计数器值-1。
任何时刻计数器为0的对象就是不可能在被使用的。但这种算法无法解决循环引用的问题。
因此Java是通过可达性分析算法来判定对象是否存活的。
GC Roots到该对象是否存在引用链就是判断对象是否存活的依据。
GC Roots对象的几种类型:
虚拟机栈中引用的对象。
方法区中类静态属性引用的对象。
方法区中常量引用的对象。
本地方法栈中JNI引用的对象。
3 引用
强引用:在程序代码中普遍存在的。这类引用不会被垃圾回收。
软引用:在内存溢出异常之前,不会被GC回收。
弱引用:生存到下一次GC发生之间。
虚引用:唯一目的在于对象被收集器回收之前收到一个系统通知
4 对象面对垃圾回收的自救
在finalize()中重新与引用链上的任何一个对象建立关联。
但finalize只会执行一次。
5 回收方法区
无用的类必须同时满足3个条件:
该类的实例都已被回收,Java堆中不存在该类的实例。
加载该类的ClassLoader已被回收。
该类对应的java.lang.Class对象没有任何地方被引用,无法在任何地方通过反射访问该类的方法。
6 垃圾回收算法
标记-清除算法--标记已经死亡的对象,然后清除这些对象的内存。
复制算法--把活着的对象复制到另一块内存区域,然后把当前这一块内存区域对象全部清除,回收内存。
标记-整理算法--标记已经死亡的对象,让存活的对象向一端移动,然后直接清理掉端边界以外的内存。
7 垃圾收集器
新生代收集器
Serial收集器
特点:单线程收集器,使用一个CPU或者一条收集线程去GC,在GC时暂停其他所有工作线程(Stop The World)。
使用场景:Clien模式下的虚拟机
ParNew收集器
特点:Serial收集器的多线程版本,同样需要Stop The World。
使用场景:Server模式下的虚拟机(目前只有它能与CMS收集器配合工作)、多CPU
Parallel Scavenge收集器
特点:他不关注缩短用户线程的停顿时间,而是关注系统有一个更高的吞吐量(用户代码时间/(GC时间+用户代码时间)),也叫“吞吐量优先”收集器
使用场景:后台运算量高的,对CPU能有较好的利用率。不适合于用户交互的程序。
老年代收集器
Serial Old收集器
特点:Serial收集器的老年代版本,使用“标记--整理”算法
使用场景:Client模式下的虚拟机使用
Parallel Old收集器
特点:Parallel Scavenge收集器的老年代版本,使用多线程和“标记--整理”算法。
使用场景:注重吞吐量以及CPU资源敏感的场合,用Parallel Scavenge + Parallel Old。
CMS收集器
特点:
1.并发收集:并发标记和并发清除过程收集器线程都可以与用户线程一起工作
2.低停顿:服务器响应速度较快,系统停顿时间短,用户体验好。
3.使用标记--清除算法: 初始标记 -> 并发标记 -> 重新标记 -> 并发清除
缺点:
1.对CPU资源敏感,占用一部分CPU资源导致应用程序变慢,总吞吐量降低。
2.无法处理浮动垃圾,由于并发清除阶段,用户线程还有垃圾产生,这部分标记后,无法在当次清除,只能下次GC清除。
3.空间碎片较多,不利于大对象分配,容易导致Full GC,这是标记--清除算法的缺点。
使用场景:
重视服务器响应速度、希望系统停顿时间短的需求。
G1收集器
特点:并发与并行、分代收集(不需要其他收集器配合)、空间整合(标记--整理)、可预测的停顿。
未完待续