1概述
垃圾回收器(Garbage Collection,GC)。
三件事:
哪些内存需要回收?
什么时候回收?
如何回收?
2对象已死
堆中几乎存放着Java世界中所有对象实例,垃圾收集器在对堆进行回收前,第一件事情就是要确定这些对象有哪些还“存活”着,哪些已经“死去”。
1、引用计数算法
基本算法是这样的:给对象添加一个引用计数器,每当有一个地方引用他时,计数器就加1;当引用失效时,计数器就减1;任何时刻计数器都为0的对象就是不可能再被使用的。
但是,Java并没有使用应用计数器,因为他很难解决对象之间的互相循环引用的问题。
2、根搜索算法
在主流的商用程序语言中(如Java和C#),都是用根搜索算法(GC Roots Tracing)判断对象是否存活。
基本思路:通过一系列的名为“GC Roots”的对象作为起点,从这个节点向下搜索,搜索所走过的路径成为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。
在Java语言里,可作为GC Roots的对象包括下面几种:
虚拟机栈(栈帧中本地变量表)中的引用的对象。
方法区中的静态属性引用的对象。
方法区中的常量引用的对象。
本地方法栈中JNI(即一般说的Native方法)的引用对象。
3、再谈引用
JDK1.2之后的扩充:强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)四种。
4、生存还是死亡?
要真正宣布一个对象死亡,至少要经历两次标记过程:
如果对象在进行根搜索后发现没有与GC Roots相连接的引用链,那他将会被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,虚拟机将这两种情况都视为“没有必要执行”。
(避免使用终结方法:http://blog.csdn.net/partner4java/article/details/7061188)
如果这个对象被判定有必要执行finalize()方法,那么这个对象将会被放置在一个名为F-Queue的队列中,并在稍后由一条由虚拟机自动建立的、低优先级的Finalizer线程去执行。
这里所谓的执行是指虚拟机会触发这个方法,但不承诺会等待他运行结束。
Demo:
类需要满足同事下面3个条件才能算是“无用的类”:
该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例。
加载该类的ClassLoader已经被回收。
该类对应的java.lang.Class对象没有任何地方被引用,无法在任何地方通过反射访问该类的方法。
5、回收方法区
方法区(或者HotSpot虚拟机中的永久代)
回收两部分:废弃常量和无用的类。
但是效果往往很差。
3垃圾收集算法
标记--清除算法
复制算法
标记--整理算法
分代收集算法
4垃圾收集器
Serial收集器
ParNew收集器
Parallel Scavenge 收集器
Serial Old 收集器
Parallel Old收集器
CMS收集器
G1收集器
5分配内存与回收策略
对象优先在Eden分配
大对象直接进入老年代
长期存活的对象将进去老年代
动态对象年龄判定
空间分配担保
垃圾回收器(Garbage Collection,GC)。
三件事:
哪些内存需要回收?
什么时候回收?
如何回收?
2对象已死
堆中几乎存放着Java世界中所有对象实例,垃圾收集器在对堆进行回收前,第一件事情就是要确定这些对象有哪些还“存活”着,哪些已经“死去”。
1、引用计数算法
基本算法是这样的:给对象添加一个引用计数器,每当有一个地方引用他时,计数器就加1;当引用失效时,计数器就减1;任何时刻计数器都为0的对象就是不可能再被使用的。
但是,Java并没有使用应用计数器,因为他很难解决对象之间的互相循环引用的问题。
2、根搜索算法
在主流的商用程序语言中(如Java和C#),都是用根搜索算法(GC Roots Tracing)判断对象是否存活。
基本思路:通过一系列的名为“GC Roots”的对象作为起点,从这个节点向下搜索,搜索所走过的路径成为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。
在Java语言里,可作为GC Roots的对象包括下面几种:
虚拟机栈(栈帧中本地变量表)中的引用的对象。
方法区中的静态属性引用的对象。
方法区中的常量引用的对象。
本地方法栈中JNI(即一般说的Native方法)的引用对象。
3、再谈引用
JDK1.2之后的扩充:强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)四种。
4、生存还是死亡?
要真正宣布一个对象死亡,至少要经历两次标记过程:
如果对象在进行根搜索后发现没有与GC Roots相连接的引用链,那他将会被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,虚拟机将这两种情况都视为“没有必要执行”。
(避免使用终结方法:http://blog.csdn.net/partner4java/article/details/7061188)
如果这个对象被判定有必要执行finalize()方法,那么这个对象将会被放置在一个名为F-Queue的队列中,并在稍后由一条由虚拟机自动建立的、低优先级的Finalizer线程去执行。
这里所谓的执行是指虚拟机会触发这个方法,但不承诺会等待他运行结束。
Demo:
- package cn.partner4java.gc;
- import java.util.concurrent.TimeUnit;
- /**
- * 此代码演示了两点:<br/>
- * 1、对象可以在被GC时自我拯救。<br/>
- * 2、这种自救的机会只有一次,因为一个对象的finalize()方法最多只会被系统自动调用一次。
- * @author partner4java
- *
- */
- public class FinalizeEscapeGC {
- public static FinalizeEscapeGC SAVE_HOOK = null;
- public void isAlive() {
- System.out.println("yes, i am still alice :)");
- }
- @Override
- protected void finalize() throws Throwable {
- super.finalize();
- System.out.println("finalize method executed!");
- FinalizeEscapeGC.SAVE_HOOK = this;
- }
- public static void main(String[] args) throws InterruptedException {
- SAVE_HOOK = new FinalizeEscapeGC();
- //对象第一次成功拯救自己
- SAVE_HOOK = null;
- System.gc();
- //因为Finalizer方法优先级很低,暂停,以等待他
- TimeUnit.MILLISECONDS.sleep(500);
- if(SAVE_HOOK != null){
- SAVE_HOOK.isAlive();
- }else {
- System.out.println("No,i am dead :(");
- }
- //下面的代码与上面的相同,但是这次拯救自己却失败了
- SAVE_HOOK = null;
- System.gc();
- //因为Finalizer方法优先级很低,暂停,以等待他
- TimeUnit.MILLISECONDS.sleep(500);
- if(SAVE_HOOK != null){
- SAVE_HOOK.isAlive();
- }else {
- System.out.println("No,i am dead :(");
- }
- }
- // 后台打印:
- // finalize method executed!
- // yes, i am still alice :)
- // No,i am dead :(
- }
类需要满足同事下面3个条件才能算是“无用的类”:
该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例。
加载该类的ClassLoader已经被回收。
该类对应的java.lang.Class对象没有任何地方被引用,无法在任何地方通过反射访问该类的方法。
5、回收方法区
方法区(或者HotSpot虚拟机中的永久代)
回收两部分:废弃常量和无用的类。
但是效果往往很差。
3垃圾收集算法
标记--清除算法
复制算法
标记--整理算法
分代收集算法
4垃圾收集器
Serial收集器
ParNew收集器
Parallel Scavenge 收集器
Serial Old 收集器
Parallel Old收集器
CMS收集器
G1收集器
5分配内存与回收策略
对象优先在Eden分配
大对象直接进入老年代
长期存活的对象将进去老年代
动态对象年龄判定
空间分配担保