虛擬機之GC收集器

  • 哪些內存需要回收?

除了程序計算器所有的內存分佈區域都可能存在內存溢出(堆(75-90%)、棧(虛擬機棧和本地方法棧)、方法區(常量池))

堆:一個接口中的多個實現類需要的內存可能不一樣,一個方法中的多個分支需要的內存也可能不一樣,我們只有在程序              處於運行期間時才能知道會創建哪些對象,這部分內存的分配和回收都是動態的,肯定需要我們去關注和回收;(

我們主要要關注這部分的回收)

棧:我們主要討論虛擬機棧(java方法調用時虛擬機爲線程分配的內存空間-其他線程不可見-隨線程而生,隨線程而                      滅),但是呢,因爲在類加載的時候已經確定了類的實例對象所需要的內存空間大小,所以我們不需要關注這塊內存的                回收問題;

方法區:因爲方法結束或者線程結束時,內存自然就跟隨着回收,我們也不需要去考慮,自動回收了;(廢棄常量和無用的類)

  • 什麼時候回收?

一般情況下:當對象不被使用了就進行回收,我們一般認爲 Object obj = null 就可以回收,但這種判斷太籠統了,垃圾回收器是怎麼做的呢?

垃圾回收器回收堆內存:

 先判斷對象是否存活?怎麼判斷存活

            方法①  引用計算算法,當對象被調用,則計算加1,沒有使用則計算減1,,如果計算爲0則判斷該對象可以回收;

但是,這種方法存在問題,當2個對象相互引用時,計算就不爲0,此刻垃圾回收器就不會回收該類對象;

 

從上面可以看出垃圾回收執行了, 對象被回收了,則說明虛擬機不是使用的此類算法判斷對象是否存活(HotSpot虛擬機)。

      方法②:可達性分析算法(虛擬機主流算法)

這個算法的基本思路就是通過一系列的稱爲“GC Roots”的對象作爲起始點,從這些節點開始向下搜索,搜索所
           走過的路徑稱爲引用鏈(Reference Chain),當一個對象到GC Roots沒有任何引用鏈相連
          (用圖論的話來說,就是從GC Roots到這個對象不可達)時,則證明此對象是不可用的。如
            圖3-1所示,對象object 5、object 6、object 7雖然互相有關聯,但是它們到GC Roots是不可達的,所以它們將會被判定             爲是可回收的對象。

 

在Java語言中,可作爲GC Roots的對象包括下面幾種:
                虛擬機棧(棧幀中的本地變量表)中引用的對象。
                方法區中類靜態屬性引用的對象。
                方法區中常量引用的對象。
                本地方法棧中JNI(即一般說的Native方法)引用的對象。

  • 怎麼回收?

​​​​​​​標記-清除算法

顧名思義,該類算法分爲“標記”、“清除”兩個階段。

第一步:將需要回收的對象進行標記;

第二步:將標記的對象進行回收。

 

缺點:①  效率,“標記”、“清除”的效率比較低;

           ②  產生大量不連續的內存空間碎片,空間碎片太多可能會導致以後在程序運行過程中需要分配較大對象時,

                 無法找到足夠的連續內存而不得不提前觸發另一次垃圾收集動作。

複製算法

    最初的定義:將容器大小將內存分爲等同的兩塊,單一塊使用完了就將該塊上面的使用的複製到另外一塊上,

    然後把當前塊清除;

優缺點:簡單、效率高,但是浪費內存空間,內存使用率降低50%;

​​​​​​​商業虛擬機:IBM公司的專門研究表明,98%的對象“朝生夕死”,什麼意思?意味着大部分的對象可以回收,我們不需要                                    按照1:1的比例分配內存,將內存分爲一塊較大的Eden空間和兩塊較小的Survivor空間,每次使用Eden和其                                  中一塊Survivor[1]。當回收時,將Eden和Survivor中還存活着的對象一次性地複製到另外一塊Survivor上,                                    最後清理掉Eden和剛纔用過的Survivor空間。HotSpot虛擬機默認Eden和Survivor的大小比例是8:1,也就是                                  每次新生代中可用內存空間爲整個新生代容量的90%(80%+10%),只有10%的內存會被“浪費”。當然,                                    98%的對象可回收只是一般場景下的數據,我們沒有辦法保證每次回收都只有不多於10%的對象存活,當                                      Survivor空間不夠用時,需要依賴其他內存(這裏指老年代)進行分配擔保(Handle Promotion)

標記-整理算法

第一步:標記
              將需要被回收的對象先“標記”出來;
第二步:整理
               讓所有的存活的對象都移動到一邊,以“邊界”爲限,清除邊界外的內存;
 
 
分代收集算法
 
     根據對象存活週期的不同將內存劃分爲幾塊  “新生代”和“老生代”,
     “新生代”:對象存活率低,每次回收有大量對象‘死去’,此刻採用“複製算法”;
     “老生代”:對象存活率高,沒有額外的空間進行‘’擔保’,此刻採用“標記-清除”或者“標記-整理”
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章