1. 程式人生 > >【轉載】jvm記憶體回收

【轉載】jvm記憶體回收

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
出處:

https://www.cnblogs.com/prophet-it/p/6498275.html