大战Java虚拟机【2】—— GC策略
前言
前面我們已經知道了Java虛擬機所做的事情就是回收那些不用的垃圾,那些不用的對象。那么問題來了,我們如何知道一個對象我們不需要使用了呢?程序在使用的過程中會不斷的創建對象,這些所創建的對象指不定在哪里我們就需要用到了呢?GC怎么知道我們不用了呢?回收就是簡單的刪除嗎?這些問題將會在這里做出解釋。
?
怎么判斷一個對象將會被回收
說白了就是判斷一個對象已經死亡,不會再被用到了。
首先我們需要知道java中有四種不一樣的引用。
強引用:A a = new A()
軟引用:還有用,但不是必須的對象,軟引用就是連著這些對象,如果馬上要內存溢出了就會嘗試回收這些對象
弱引用:被弱引用關聯的對象只能活到下一次GC之前
虛引用:最沒用的一個,只有一個目的,在回收之前收到一個系統通知
?
引用計數(這個不是java虛擬機使用的)
看書的時候我就驚訝了,因為我確實也面試到很多人這個問題,回答告訴我的都是引用計數,即:用一個計數器,當有引用指向它,則加1,當失去一個引用,則減1,當引用為0時則回收。
我學過AS3,在flash里面確實是這樣的,但是在java虛擬機里面不是,因為沒有辦法回收兩個互相引用的對象。
比如A引用B,B引用A這樣大家引用都不是0,就無法回收了,顯然java中是可以回收這樣對象的。
?
可達性算法
引入了GC Root的概念,從這個根必須能引用到這個對象。
(GC Root)->(A)->(B)
???????????????????????????????????????????????? (C)
當C這樣的對象到GC Root沒有任何引用鏈項鏈的時候,也就是不可達的時候,算這個對象已經死亡。
java和C#都是使用這樣算法。
?
上面說的都是堆中對象的死亡條件,或者說堆的的對象什么時候會被回收。
我們要知道的是,方法區其實也是可以垃圾收集的。比如當一個字符串常量沒有地方引用到了這個量,如果現在方法區不夠了那就會進行回收。
?
?
垃圾收集的算法
這里用最簡單的話概括一下,有必要的詳細了解
1、標記-清除
看名字就知道,就先標記一下要回收的對象,標記完成之后統一清除。
缺點:效率不高,清除之后碎片內存太多。
2、復制
將內存一分為A、B;用的時候就用A這塊,回收的時候,將A中需要用的東西復制到B中,然后一次性清除A的區域。
優點:對象存活率不高的時候效率高,不會有內存碎片,都是一整塊的。
缺點:代價高,原本挺大的一塊內存硬生生是被切成了一半。(不是說所有的虛擬機都是對半分來實現復制的)
3、標記-整理
和標記清除類似,只是在清除的時候不一樣,這里是整理,將存活的對象移到一起。
效率和標記清除是差不多的,但是不會有碎片內存
4、分代收集
因為不是每個收集的算法都是完美的,所以java虛擬機采用分代收集的思想,對于新生代因為有大批的對象會死亡,所以使用復制,但是對于老年代,對象的存活率高,所以采用標記整理或者標記清除。
?
分配
我們知道了對象是如何回收的,同時我們也需要知道對象是如何分配的。
1、對象優先分配在新生代Eden區,當沒有位置的時候發起一次MinorGC
2、大的對象,如連續分配的數組直接進入老年代
3、長期存活的對象會進入老年代,沒熬過一次MinorGC就增加一歲
4、當相同年齡的對象大小綜合大于Survivor的一半就會將年齡大于等于這個年齡的對象直接進入老年代
5、老年代可以用作新生代的空間擔保,新生代用的是復制算法,萬一對象存活太多,那么需要額外的空間去彌補
?
針對每個收集器的具體行為和優勢劣勢將會在后面提出,這里暫時就到這里。
上面就是GC策略,我們所要知道的就是如何判斷一個對象存活,對象怎么被回收,對象怎么被分配。
?
新人創作打卡挑戰賽發博客就能抽獎!定制產品紅包拿不停!總結
以上是生活随笔為你收集整理的大战Java虚拟机【2】—— GC策略的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 53亿美元,今年最大一笔杠杆并购案!为什
- 下一篇: 解决mysql 1040错误Too ma