JVM Garbage Collection(垃圾回收机制) 一

写在前面的话:本文是作者在阅读了文章底部的相关网站链接后,整理得出的学习资料,并非完全原创,切勿私自拷贝用作商业用途,欢迎大家留言进行学术讨论。如有侵犯到他人权利,请联系本人进行删除,谢谢合作!

1.什么时候回出发对象的回收?
答:a.对象没有引用
    b.作用域发生未捕获异常
    c.程序在作用域正常执行完毕
    d.程序执行了System.exit()
    e.程序发生意外终止(被杀进程等)

2.是不是一个对象被赋值为null以后就一定被标记为可回收对象了呢?
答:并不是所有对象被赋值为null之后就一定被标记为可回收,有可能会发生逃逸!

3.常见的垃圾收集算法
答:
(a)JDK1.2之前,使用的是引用计数器算法。即当这个类被加载到内存以后,就会产生方法区,堆栈、程序计数器等一系列信息。
(1)当创建对象的时候,为这个对象在堆栈空间中分配对象,同时会产生一个引用计数器,同时引用计数器+1。
(2)当有新的引用的时候,引用计数器继续+1。
(3)而当其中一个引用销毁的时候,引用计数器-1。
(4)当引用计数器被减为零的时候,标志着这个对象已经没有引用了,可以回收了!
上述算法带来的问题:
example:
ObjA.obj = ObjB & ObjB.obj = Obj.A
即 对象A指向对象B 同时 对象B又指向对象A 当其他额外的引用消失后 对象A和对象B之间还存在一个相互的引用关系,然而二者皆已为垃圾,可以被回收了。

(b)跟搜索算法
程序把所有的引用关系看作一张图,从一个节点GC ROOT开始,寻找对应的引用节点,找到这个节点以后,继续寻找这个节点的引用节点,当所有的引用节点寻找完毕之后,剩余的节点则被认为是没有被引用到的节点,即无用的节点。

    -----------
    | GC root |
    -----------
             |
    -----------
    |   ObjA   |
    -----------
           /    \
         /        \
-----------    -----------    -----------
|   ObjB   |    |   ObjC    |    |   ObjD  |
-----------    -----------    -----------
      |                    |
-----------    -----------    -----------
|   ObjF   |     |      ....     |    |   ObjE   |
-----------    -----------    -----------

根据上图,获取从GC root 出发的引用关系:
          ObjB
        /
GC root -> ObjA    
        \
          ObjC    — ....

未被引用到的节点有 ObjD、ObjF、ObjE

java中可以作为GC Root的对象(本地变量表)
1.虚拟机栈中引用的对象
2.方法区中静态属性引用对象
3.方法区中常量引用对象
4.本地方法栈中引用的对象(Native对象)


4.java中的引用及其分类
(a)强引用
***只要强引用在,垃圾回收器永远不会回收
example:Object obj = new Object();

(b)软引用
**非必须引用,内存溢出之前进行回收
example:
Object obj = new Object();
SoftReference<Object> sf = new SoftReference<Object>(obj);
obj = null;
sf.get();//有时候会返回null

sf对obj是一个软引用。通过sf.get()取到这个对象。
软引用类似用户实现缓存的功能,内存足够的情况下直接通过软引用取值提升速度,若内存不足,则删除这部分缓存数据,从真正的来源查询这些数据。

(c)弱引用
**第二次垃圾回收时回收
example:
Object obj = new Object();
WeakReference<Object> wf = new WeakReference<Object>(obj);
obj = null;
wf.get();//有时候会返回null
wf.isEnQueued();//返回是否被垃圾回收器标记为即将回收的垃圾

短时间内通过弱引用取对应的数据,可以取得,但当执行第二次垃圾回收时,将返回null值

(d)虚引用(幽灵/幻影引用)
*垃圾回收时回收,无法通过引用取得对象值
example:
Object obj = new Object();
PhantomReference<Object> pf = new PhantomReference<Object>(obj);
obj=null;
pf.get();//永远返回null
pf.isEnQueued();//返回从内存中已经删除

每次垃圾回收的时候都会被回收,通过虚引用取到的对象值永远为null。主要用于检测对象已经从内存中删除。


5.对象在内存中的区域划分
对象在内存中回被分成5个区域,而每个区域的回收比例是不同的
(1)方法区     5%
(2)Java堆     70%-95%
(3)Java栈     100%
(4)程序计数器 0%
(5)本地方法栈 100%

(a)方法区主要存放类与类之间的数据,这部分被加载到内存后基本不会改变
(b)Java堆中的数据,用完之后马上进行回收
(c)Java栈中的数据遵循后进先出的原则,在取下数据之前,要先把栈顶的元素进行出栈,因而回收率为100%
(d)程序计数器,记录线程执行的信号等信息。该区域是唯一不会内存溢出的区域
(e)本地方法栈同(C)

注释:sunhostspot中方法区的数据因为回收率非常小,而且成本又高,性价比非常差。所以在sunhostspot虚拟机中是不回收的。但是在高性能分布式J2EE的系统中方法区也是会被回收的(自定义加载器导致类经常被加载和卸载),但是需满足一下苛刻条件:(1)所有实例被回收(2)加载该类的ClassLoader被回收(3)Class对象无法通过任何途径访问(包括反射)


6.垃圾收集后的回收算法
在3.中提到了垃圾的收集算法,而在收集之后要面临的就是垃圾回收机制,其算法有如下几类
(1)标记-清除算法
(2)复制算法
(3)标记-整理算法

(a)标记-清除算法
图一:引用关系图(根目录->A->C)
     ---------------
     |       引用      |
 ---------         -------------------
 |根目录 |         |  A  |  B  |  C  |     |    空闲表
 ---------         -------------------        |
                          |   引用    |      |          |
                          -----------     ---------

*******************分割线*************************

图二:第一步,从根目录开始扫描对存活的对象进行标记(标记的内存带$)
     -------------
     |       引用    |
 ---------       ---------------------
 |$根目录|      | $A  |  B  | $C  |     |    空闲表
 ---------       ---------------------         |
                         |   引用    |       |             |
                         -----------      -----------

*******************分割线*************************

图三:第二步,标记完成后,再扫描整个空间中未被标记的空间,进行回收(回收了B)
     --------------     ----------------
     |       引用    |     |                       |
 ---------      ------------------       |
 | 根目录|      |  A  |     |  C  |     |    空闲表
 ---------    --------------------       |
                       |   引用    |     |          |
                       -----------     --------

*******************分割线*************************

标记-清除的算法不需要进行对象的移动,并且处理对象仅为未标记对象。若存活对象较多的情况下极为高效。但是由于对象不可移动,且直接回收不存活对象,会产生内存碎片。(如图三种B空间被回收后A、C之间产生内存碎片)。

(b)复制算法
图一:引用关系图(根目录->A->C)
     ---------------
     |       引用      |
 ---------         -------------------
 |根目录 |         |  A  |  B  |  C  |     |    空闲指针
 ---------         -------------------        |
                          |   引用    |   |              |
                          -----------  -----------

*******************分割线*************************

图二:从根目录扫描,将存活对象复制到一块新的,未被使用的空间
     ---------------
     |       引用       |
 ---------         --------------------
 |根目录 |          |  A  |  B  |  C  |     |    空闲指针
 ---------          -------------------       |
                        | |   引用    |  | |             |
                    复 | ----------  |  -----------
                    制 |                  |
                        |          -------       
                        |          |  复制
                        -------------------
                         |  A  |  c  |           |          空闲指针
                         ------------------                 |
                                        |                            |
                                        ---------------------                                                         
*******************分割线*************************
复制算法采用从更目录开始扫描,并将存活的对象复制到一块新的,未被使用的空间。在存活对象较少的情况下极为高效。但是由于需要进行对象移动,所以需要一块内存交换空间
                
(c)标记-整理算法
图一:引用关系图(根目录->A->C)
     -------------
     |       引用    |
 ---------         -------------------
 |根目录 |         |  A  |  B  |  C  |     |       空闲指针
 ---------         -------------------               |
                        |     引用      | |                    |
                        -------------  ---------------

*******************分割线*************************
图二:第一步,从根目录开始扫描对存活的对象进行标记(标记的内存带$)
     -------------
     |       引用    |
 ---------         ----------------------
|$根目录 |         |  $A  |  B  |  $C  |     |       空闲指针
 ---------         ----------------------                  |
                        |     引用      |     |                        |
                        -------------      ------------------

*******************分割线*************************
图三:回收不存活对象,并且整理存活对象,消除内存空间
     ---------------
     |       引用       |
 ---------         -------------------------
 |根目录 |         |  A  |  C  |                     |    空闲指针
 ---------         -------------------------       |
                          |引用 |  |                            |
                          -------  ---------------------
                   
*******************分割线*************************

标记-整理算法采用和标记-清除算法一样的手法对对象进行标记,但在回收不存活的对象占用的空间后,将所有存活的对象往左端移动,并更新对应指针。成本最高,但是解决的内存碎片的问题。

相关参考网站:
http://blog.youkuaiyun.com/achuo/article/details/45250077
http://jbutton.iteye.com/blog/1569746
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值