`

深入理解java虚拟机读书笔记-第三章

    博客分类:
  • JVM
阅读更多

==============对象是否生存======================

    引用计数法:

     给对象添加一个引用计数器,每当有一个地方引用它的地方,计数器值+1;当引用失效,计数器值就减1;任何时候计数器为0,对象就不可能再被引用了。

     引用计数法的缺陷(相互引用)p63

      

ReferenceCountingGc A=new ReferenceCountingGc ();
ReferenceCountingGc B=new ReferenceCountingGc ();
A.instance=B;
B.instance=A;
A=null;
B=null;

    在这个场景下,A,B的计数器应该为1,但是AB却没有被引用。在GC时,AB被回收掉,说明JVM不是使用的计数器。

   

    可达分析性算法

    算法的基本的思想是通过一系列的称为"GC ROOTS"的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连,就说明对象不可用。

    可以作为Gc Roots的对象包括下面几种:

深入理解java虚拟机
虚拟机栈的本地变量表中引用的对象。
方法去中类静态属性引用的对象。
方法区中常量引用的对象。
方法区栈中JNI引用的对象。

    

 ========根据引用的生命周期长短分类(以下是我自己的理解不是书里==========================

强引用(Strong Reference)

    即代码中普遍存在的new 出来的对象引用。在对象未存活时,被gc掉。

软引用(SoftReference)

    继承自SoftReference或者使用new SoftReference(new Object()),如果放入SoftReference的对象A,除了softreference以外没有其他地方引用,那么JVM在full gc时会回收掉此引用。

弱引用(weakReference)

     同SR,不过如果没有其他地方引用,会在下一次GC时回收掉。

虚引用(PhantomReference)

     不会对对象的生存时间构成影响,只是在对象被收集器回收时收到一个系统通知。

 

=================Finalize()方法=============================== 

 

要真正宣告一个对象是死亡的,至少经历两次标记过程,如果对象在进行可达分析后发现没有引用链,则会标记一次毕竟进行筛选,筛选的条件是此对象是否有必要执行finialize().当对象没有覆盖finialize()方法或者finalize()方法已经被虚拟机调用,则被视为”没有必要执行“。

   对于有必要执行的情况,对象会被放到一个F-Queue队列里,由一个低优先级的Finalizer线程去执行。但所谓执行,并不承诺会等待它结束,这样的做的原因是finalize()方法可能会很慢或者死循环,导致F-Queue队列的其他对象处于等待。稍后GC会对F-Q里的对象第二次标记,如果F方法没有再次将对象进行关联,那么他将会被回收。另外finallize()方法只会被系统调用一次。

 

 

===================垃圾回收算法=================================

算法1:标记清除算法(Mark-Sweep)

             分为标记和清除两个阶段。

             缺陷:效率问题,产生大量不连续空间。(个人理解适合不频繁内存区域的回收)

 

算法2:复制算法 (Copying)

             分配两个大小相同的的块,每次只是用一块,当这一块的内存用完时,将还存活的对象复制到这一块上面。并把之前是用的块清空。

              在新生代回收算法中,Eden Suvivor去按照8:1:1的比例分配。当回收时,将Eden和Survivor中还存活的对象一次性地复制到另一块Survivor区中,并清理掉Eden区和刚才用过的Survivor区。

               我们没有办法保证每次回收都只有不到10%的对象存活,当Survivor空间不够用时,需要其他内存(老年代)进行担保。如果另一块Survivor空间没有够用空间存放上次新生代收集下来存活的对象时,这些对象将直接分配担保机制进入年老代。

             

=============一些回收规则=============================

1.大多数情况下,对象在新生代Eden分配。当Eden区没有足够空间进行分配,虚拟机会进行一次Minor GC。MGC发生的一般比较频繁,而且回收速度也很快。

2.大对象直接进入年老代。虚拟机提供一个-XX:PretenureSizeThreshold参数,令大于这个设置值的对象直接在老年代分配。这样做的目的是避免在Eden区及两个Survivor区之间发生大量的内存复制。

3.长期存活的对象进入年老代。虚拟机给每个对象定义一个对象年龄计数器。如果对象在Eden出发并经过第一次 MinorGC后仍然存活,并且能够被Survivor容纳话,将会被移动到Survivor区中,并将对象年龄设为1.对象在Survivor区经历过一次MGC,年龄就会加1。当对象年龄增加到一定程度,默认15岁时,就会被晋升到老年代。晋升的阈值,通过-XX:MaxTenuringThreshold设置。

4.动态对象年龄判定。如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代。无需等MaxTenuringThreshold。

5.空间分配担保。JDK 6Update 24之后规则变为只有老年代的连续空间大于新生代对象总和或者历次晋升的平均大小就将会进行MGC,否则进行FGC.

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics