Java內存回收機制.md

1.java的內存

java的內存結構分爲

  • 堆 (是gc的主要區域) 線程共享,主要是用於分配實例對象和數組
  • 棧 線程私有,它的生命週期和線程相同,又分成 虛擬機棧和本地方法棧,只有它會報 StackOverFlowError,棧深度超標
  • 方法區 線程共享 用於儲存被虛擬機加載的類的信息,靜態變量 常量和編譯後的.class字節碼
  • 程序計數器 線程私有,線程之間不相互影響,獨立存取;
    以上部分,線程私有是不會發生gc.並且他們是隨線程生隨線程滅,即程序計數器 本地方法棧和虛擬機棧
    來張圖更詳細

2.GC回收機制--判斷是否可以gc

  • 引用計數算法
    原理:通過一個計數器對對象進行計數,對象被引用時+1,引用失效時-1;當計數爲0時則說明可以被回收;
    缺點:很難解決對象的相互循環引用問題
  • 可達性分析算法
    Java虛擬機所採用的算法;
    原理:通過一些列稱爲“GC Roots”的對象作爲起始點,從這些節點開始向下搜索,搜索所走過的路徑稱爲引用鏈,當一個對象到GC Roots沒有任何引用鏈相連時,則證明此對象是不可用的。
    那麼哪些對象可以被稱爲gc roots呢----虛擬機棧(棧中的本地變量列表)/方法區靜態屬性/方法區常量引用/本地方法棧中JNI 所引用的的對象都是可以作爲 gc roots的

3.GC回收機制--如何回收

  • 標記清除算法
    清除算法分成2個階段--標記和清除; 標記階段對所有存活的階段進行標記,標記完成後,再掃描整個空間未標記對象,直接回收不存活的對象.
    優點:大多數情況下比較高效,缺點是會造成內存碎片,碎片太多導致後面過程中對大內存的分配無足夠空間時而提前猝發一次垃圾回收動作;
  • 複製算法
    將可用內存將容量劃分成大小相等的2塊,每次清理時將其中A內存還存活的對象複製到B內存裏面,然後再把A中清理掉;
    優點高效且並不產生碎片,缺點犧牲了一半的內存爲代價
    適用存活對象少,回收對象多
  • 標記整理算法
    該算法標記階段和標記清除算法一樣,完成標記後它不是直接清理可回收對象,而是將存活對象都向一端移動最後清理掉端邊界意外的內存;
    適用於存活對象多,回收對象少的情況
  • 分代收集算法
    整合了複製算法和標記整理算法,根據新生代和老年代的不同特性採取上面的不同算法
    新生代 生命週期短,每次回收時都有大量垃圾對象需要回收 複製算法
    老年代 每次只有少量的對象需要回收 標記整理算法

深入理解分代回收算法 Survivor(倖存者) Eden (谷歌翻譯爲伊甸園)

  • 複製算法中內存劃分其實並不是按照1:1來劃分老年代和新生代,,而是按照8:1:1分一個大的Eden區和兩個小的survivor的空間
  • 爲什麼需要2個Survivor區 新生代一般經歷15次Gc就可以移到老年代.當第一次gc時,我們可以把Eden的存活對象放入Survivor A空間,第二次Gc時,Survivor A也要使用複製算法,存活對象放到Survivor B上,第三次gc時,又將Survivor B對象複製到Survivor A上如此循環往復;
  • 爲什麼Eden這麼大,因爲新生代中存活的對象,需要轉移的Survivor 的對象不多,算是緩解了複製算法的缺點;

4.GC回收機制--gc的執行機制

  • Scavenge GC
    當新對象生成並且在Eden申請空間失敗時就會觸發Scavenge GC;Eden區的gc會比較頻繁
  • Full GC
    是對整個堆進行清理,要比Scavenge GC要慢,什麼情況要進行Full GC呢,如下四種:
    持久代被寫滿
    System.gc調用
    老年代被寫滿
    上一次GC之後Heap的各域分配策略動態變化

持久代:
用於存放靜態文件,如今Java類、方法等。持久代對垃圾回收沒有顯著影響,但是有些應用可能動態生成或者調用一些class

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章