Jvm中的記憶體回收,Jvm記憶體回收
一、記憶體回收的概念
Java中的記憶體回收即Jvm運行時的記憶體的回收,需要回收的地區有方法區和Java堆。由於程式計數器,Java虛擬機器棧和本地方法棧在方法結束或者是線程結束時會自動進行回收所以無須考慮回收。為什麼需要記憶體回收呢?因為電腦中的記憶體的大小是有限而固定的,在運行過程中由於類的載入和建立,記憶體中已使用的記憶體會越來越大,導致後來的程式執行時無法進行分配記憶體進行執行,此時就需要進行記憶體回收,將已經使用的記憶體地區中沒有在使用的資料清除,從而使後來的程式能夠正常運行。
二、如何判斷一個對象可以進行回收?
在進行記憶體回收的時候,如何判斷一個對象是否已經可以進行回收了呢?一個對象可以進行回收的時候就是不再有變數引用這個對象。常規去判斷一個對象是否還有變數引用,使用的是引用計數法。就是給對象添加一個引用計數器,如果一個變數引用了這個對象,就把計數器裡面的值加一,引用失效時就減一。進行記憶體回收的時候,對計數器裡面的值為零的對象進行回收。但是主流的Java虛擬機器並沒有採用此種方法進行記憶體回收,而是採用GC Roots可達性演算法進行判斷一個對象是否可以進行回收。
採用GC Roots可達性演算法進行判斷對象是否回收時,就是通過一系列可以作為GC Roots的對象作為起始點,向下搜尋對象,形成多條對象可以GC Roots對象的路徑,稱為引用鏈,當一個對象不存在這個引用鏈中時,就可以進行回收。
圖中的對象A、B、C、D都存在路徑(引用鏈)到達GC Roots對象,F則不存在,所以進行記憶體回收會回收對象F,而不會回收對象A,B,C,D。
三、記憶體回收演算法
Jvm中的記憶體回收使用以下幾種回收演算法:
1.標記-清除演算法:在進行記憶體回收的時候,將不再引用的對象進行標記,標記完成後,統一對於標記的對象進行回收。
未回收時:
進行標記-清除時,會對未引用對象進行全部標記,在標記完成後,對標記的未引用對象的記憶體進行回收。
標記-清除後:
2.標記-整理演算法:在進行記憶體回收的時候,將不再引用的對象進行標記,標記完成後,統一對於標記的對象進行回收後,對記憶體進行整理,將引用對象移動到一起
標記-整理之前:
如同標記-清除方法一樣,會對未引用對象進行標記,標記完成後進行清除,然後將還在引用對象的記憶體移動到一起
標記整理後:
3.複製演算法::將記憶體劃分成相等的兩塊記憶體,每次只使用其中一塊記憶體進行分配,當正在使用記憶體中的空間使用完畢時,將使用的記憶體中的還存活的對象複製到另一塊未使用的記憶體上,然後將清理已使用記憶體的空間。
回收之前:
複製演算法回收之後:
4.分代演算法:將回收區分為新生代和老年代,新生代採用複製演算法,老年代採用標記-清除或者是標記-整理演算法
四、垃圾收集器
垃圾收集器就是記憶體回收演算法的具體實現。Jvm中存在一下幾種垃圾收集器
1.Serial收集器:使用單線程對於垃圾進行回收,進行記憶體回收時必須停掉所有得背景工作處理序進行記憶體回收,使用標記-整理演算法。
2..Serial Old收集器:Serial收集器的老年代版本。
3.ParNew收集器:Seria收集器的多線程版本。
4.Parallel Scavenge收集器:採用複製演算法的收集器,控制輸送量進行垃圾收集的演算法,輸送量即CPU運行使用者代碼的時間與CPU運行總時間的比值,使用者可以通過設定輸送量來控制記憶體回收的效率。
5.Parallel Old收集器:Parallel Scavenge的老年代版本,採用標記整理演算法和使用多線程回收。
6.CMS收集器:以獲得最短回收停頓時間為目標的收集器,採用標記-清除演算法。回收的流程為:初始標記->並發標記->重新標記->並發清除.
7.G1收集器:最新的收集器,回收流程為:初始標記->並發標記->最終標記->篩選回收。