java中的gc垃圾回收机制

来源:互联网 发布:php空间 编辑:程序博客网 时间:2024/05/16 06:41

1、所谓垃圾回收机制:是JVM对堆内存区域的回收

2、怎样确定一个线程是否可以被回收:

方法一:计数法:在内存中用计数器记录该对象被引用的次数,当被引用时就+1,对象释放就-1,当计数器中数为0时说明是该回收的线程了。但是这种方法有漏洞:当A 和B两个对象相互引用形成循环,那么计数器中的数就一直是1,这样就不会被察觉得到。这样就用到了

第二种方法:

 3


方法二:根搜索:就是找这个对象有没有路径可以到达根,如果有则不回收,如果没有那么进行回收。

如下图:对象D访问不到根对象,所以就会被回收

4

以下对象会被认为是root对象:

  • 被启动类(bootstrap加载器)加载的类和创建的对象
  • jvm运行时方法区类静态变量(static)引用的对象
  • jvm运行时方法去常量池引用的对象
  • jvm当前运行线程中的虚拟机栈变量表引用的对象
  • 本地方法栈中(jni)引用的对象
3、在根搜索所得到的回收对象前有一个复活环节:有且仅有一次复活机会,如果不能复活,那么就会永远死去,呵呵。实现他的函数是finalize(),我们要重写一下:

package deadToLive;/** * Created by Administrator on 2015/11/3 0003. */public class DeadToAlive {    private static DeadToAlive deadToAlive;    public void finalize() throws Throwable{        try {            super.finalize();            DeadToAlive.deadToAlive=this;        } catch (Throwable throwable) {            throwable.printStackTrace();        }    }    public static void main(String[] args) throws InterruptedException {        DeadToAlive.deadToAlive=new DeadToAlive();        DeadToAlive.deadToAlive=null;        System.gc();        Thread.sleep(500);        if(deadToAlive!=null)            System.out.println("Alive");        else            System.out.println("Dead");        DeadToAlive.deadToAlive=null;        System.gc();        Thread.sleep(500);        if(deadToAlive!=null)            System.out.println("Alive");        else            System.out.println("Dead");    }}
首先标记一次,将其放在F-queue队列中,等待执行finalize()函数,执行后GC进行二次标记,而此时赴会的不会被标记,只有在执行完finalize()后仍然dead的那么就直接进行回收了。

4、垃圾回收的策略:

(1)标记--清除:直接将内存中二次标记的的线程进行消除,这样简便但是会造成碎片的产生,内存的浪费。

(2)标记--复制:将堆分成8:1:1的1个Eden和2个survivor构成新生代。

每次将Eden和Survivor中存活的对象
复制到另一块空闲的Survivor中。这三块区域并不是堆的全部,而是构成了新生代

从下图可以看到这三块区域如何配合完成GC的,具体的对象空间分配以及晋升请



为什么不是全部呢?如果回收时,空闲的那一小块Survivor不够用了怎么办?这就是
老年代的用处。当不够用时,这些对象将直接通过分配担保机制进入老年代。那么
老年代也使用标记-复制策略吧?当然不行!(老年代是使用标记--整理策略)老年代中的对象可不像新生代中的,
每次回收都会清除掉大部分。如果贸然采用复制的策略,老年代的回收效率可想而知。
(3)标记--整理:将所有Alive下来的线程都整理到一块去,这样解决了(1)的局限性,并且满足老年代的特点。


5、虚拟机上的收集器:

(1)新生代的GC:

serial:单线程,当他进行回收时,其它工作线程必须暂停

parNew:多线程

parallel scavenge:吞吐量优先

(2)老年代的GC:
serial old:单线程

parallel old:多线程

CMS:是基于标记--清除

6、什么情况下进行GC:

(1)新生代回收:

Minor GC(新生代回收)的触发条件比较简单,Eden空间不足就开始进行Minor GC回收新生代。
(2)老年代回收:

(1)老年代空间不足
(2)PermSpace空间不足
(3)统计得到的Minor GC晋升到老年代的平均大小大于老年代的剩余空间
这里注意一点:PermSpace并不等同于方法区,只不过是Hotspot JVM用PermSpace来
实现方法区而已,有些虚拟机没有PermSpace而用其他机制来实现方法区。
7、要回收对象空间分配和晋升:
对象优先分到新生代的Eden中
大对象分配到老年代中
新生代中的对象每熬过一次Minor GC就会+1岁,当为15岁时就会进入老年代


资源来源:http://blog.csdn.net/dc_726/article/details/7934101

1 0