-------------- 本文参考自<<深入理解jvm虚拟机>>
判断一个对象是否需要回收,我们可以有2种方式,一种是基于引用计数的,这个我们用的比较多,比如c++的智能指针,但是无法解决循环引用的问题。 另一种是根搜索算法,通过一系列的"root"对象,往下查找引用链。没有被所有"root"对象的引用链连接起来的对象,即可判断为垃圾对象。在java中,可以被认为"gc root"的对象有:
- 虚拟机栈(栈桢中的本地变量表)中的引用的对象。
- 方法区的静态属性引用的对象。
- 方法区中的常量引用的对象。
- 本地方法栈中jni的引用的对象。
根据对象存在的必需程度,分为强引用,软引用,弱引用,虚引用。软和弱的区别:除非将要发生oom,否则不会清除软引用;弱引用通常在下次gc的时候就回收了。
2.垃圾收集算法
2.1 标记 - 清除法(Mark Sweep)
标记出需要被回收的对象,然后统一清除。 缺点:1.效率不高(为什么?);2.内存碎片。
2.2 复制算法
用两个一样大的内存空间,gc时,将块A存活的对象全部考到块B,然后清除块A。优点:解决标记-清除法的内存碎片问题。缺点:空间利用率50%。
改良方案: 因为新时代的对象98%都是朝生夕死,所以分配一块大的(80%)eden 空间,两块小的(10%)的survivor,将eden和一块survivor的存活对象拷到另一块survivor中,这样空间利用率有90%。问题解决:存活区的空间被压缩了,如果拷贝时survivor空间不够用,那么将直接把当次的所有存活对象考到老年代。
2.3 标记-整理法 (Mark Compact)
和标记-清除法类似。标记完以后,将对象向一端移动,然后直接清除掉边界以外的内存。
3.垃圾收集器
如果两个收集器间存在联系,则他们可以配合使用。3.1-3.3是新生代收集器,后面的收集器用于老年代。
3.1 Serial(连续的)收集器
特点:单线程,复制算法,“stop the world”,高效但是需要一个连续的时间来收集垃圾,以至于无法响应用户代码,适用于client模式。
3.2 ParNew(新式)收集器
特点:Serial的多线程版本,复制算法,“stop the world”,server模式首选,因为只有他和Serial可以配合CMS收集器工作。使用-XX:UseParNewGC 来指定他作为新生代的垃圾回收收集器。
3.3 Paraller Scavenge收集器
和ParNew类似,新生代,复制算法。特点:cpu吞吐量更大,因而适用于计算而不是用户交互。
3.4 Serial Old收集器
Serial的老年代版本,单线程,使用标记-整理法,适用于client模式。
3.5 Paraller Old收集器
Paraller Scavenge 的老年代版本,多线程,使用标记-整理算法,通常配合Paraller Scavenge使用,用于cpu和吞吐量敏感的场合。
默认情况下的垃圾收集器组合。
Server模式: Paraller Scavenge + Paraller Old
Client模式: Serial + Serial Old