第3章 垃圾收集器与内存分配策略

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:
view plain copy to clipboard print ?
  1. package cn.partner4java.gc;  
  2.   
  3. import java.util.concurrent.TimeUnit;  
  4.   
  5. /** 
  6. * 此代码演示了两点:<br/> 
  7. * 1、对象可以在被GC时自我拯救。<br/> 
  8. * 2、这种自救的机会只有一次,因为一个对象的finalize()方法最多只会被系统自动调用一次。 
  9. * @author partner4java 
  10. * 
  11. */  
  12. public class FinalizeEscapeGC {  
  13.     public static FinalizeEscapeGC SAVE_HOOK = null;  
  14.       
  15.     public void isAlive() {  
  16.         System.out.println("yes, i am still alice :)");  
  17.     }  
  18.   
  19.     @Override  
  20.     protected void finalize() throws Throwable {  
  21.         super.finalize();  
  22.         System.out.println("finalize method executed!");  
  23.         FinalizeEscapeGC.SAVE_HOOK = this;  
  24.     }  
  25.       
  26.     public static void main(String[] args) throws InterruptedException {  
  27.         SAVE_HOOK  = new FinalizeEscapeGC();  
  28.           
  29.         //对象第一次成功拯救自己  
  30.         SAVE_HOOK = null;  
  31.         System.gc();  
  32.           
  33.         //因为Finalizer方法优先级很低,暂停,以等待他  
  34.         TimeUnit.MILLISECONDS.sleep(500);  
  35.           
  36.         if(SAVE_HOOK != null){  
  37.             SAVE_HOOK.isAlive();  
  38.         }else {  
  39.             System.out.println("No,i am dead :(");  
  40.         }  
  41.           
  42.         //下面的代码与上面的相同,但是这次拯救自己却失败了  
  43.         SAVE_HOOK = null;  
  44.         System.gc();  
  45.           
  46.         //因为Finalizer方法优先级很低,暂停,以等待他  
  47.         TimeUnit.MILLISECONDS.sleep(500);  
  48.           
  49.         if(SAVE_HOOK != null){  
  50.             SAVE_HOOK.isAlive();  
  51.         }else {  
  52.             System.out.println("No,i am dead :(");  
  53.         }  
  54.     }  
  55. //  后台打印:  
  56. //  finalize method executed!  
  57. //  yes, i am still alice :)  
  58. //  No,i am dead :(   
  59. }  


类需要满足同事下面3个条件才能算是“无用的类”: 
该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例。 
加载该类的ClassLoader已经被回收。 
该类对应的java.lang.Class对象没有任何地方被引用,无法在任何地方通过反射访问该类的方法。 


5、回收方法区 
方法区(或者HotSpot虚拟机中的永久代) 
回收两部分:废弃常量和无用的类。 
但是效果往往很差。 



3垃圾收集算法  

标记--清除算法 
复制算法 
标记--整理算法 
分代收集算法 


4垃圾收集器  

Serial收集器 
ParNew收集器 
Parallel Scavenge 收集器 
Serial Old 收集器 
Parallel Old收集器 
CMS收集器 
G1收集器 


5分配内存与回收策略  

对象优先在Eden分配 
大对象直接进入老年代 
长期存活的对象将进去老年代 
动态对象年龄判定 
空间分配担保 

你可能感兴趣的:(第3章 垃圾收集器与内存分配策略)