jvm垃圾回收机制_干货|JVM垃圾回收机制
前言
不同于C++程序員必須自己完成內存的分配、使用和釋放,JAVA語言提供了垃圾回收機制(GC,Garbage Collection),所以JAVA程序員僅需要負責分配和使用內存即可,而釋放內存則由GC負責。這樣程序員就從討厭的內存管理的工作中脫身了。本文主要給大家介紹一下JVM如何查找需要被回收的對象實例與垃圾收集算法。
查找可回收對象
我們都知道垃圾回收機制是將內存中不可能在被使用的的對象實例(可回收的對象實例)回收釋放其所占用的內存,以供其他對象使用。JAVA的垃圾回收機制是對JAVA堆和方法區的內存回收。那么CG是怎么知道該對象是否還會使用呢?
一、引用計數算法(Reference Counting)
引用計數算法簡單的講就是給每個對象中添加一個引用計數器, 每當有一個地方引用它時,計數器值就加1:當引用失效時,計數器值就減1,當對象的計數器為0就表示該對象已“死”,可以被回收了。雖然這種算法實現簡單,判定效率也高。但是大部分JAVA虛擬機卻沒有使用此算法,因為這個算法很難解決對象之間互相循環引用的問題。
二、可達性分析算法(Reachability Analysis)
可達性分析算法是通過被稱為 “GC Roots" 的對象作為起始點, 從這些節點開始向下搜索,搜索所走過的路徑稱為引用鏈(Reference Chain),當一個對象到GC Roots沒有任何引用鏈相連,就是從GC Roots到這個對象不可達時,則證明此對象是不可用的。如圖1.1。對象 2、對象 4、對象 6不可到達GC Roots所以會被回收。
圖1.1垃圾收集算法
通過上文我們知道了JVM如何查詢需要被回收的對象實例,那么JVM是通過什么方法把對象收回的呢?不同虛擬機回收內存的方法各不相同,主流的方法有標記-清除算法、復制算法、標記-整理算法和分代收集算法。
一、標記-清除算法(Mark-Sweep)
標記-清除算法分為“標記”和“清除”兩個階段:首先標記出所有需要可收的對象,在標記完成后統一回收所有被標記的對象。如上文所介紹,標記過程其實就是找出不可能在被使用的對象實例。如圖1.2首先標記出需要被回收的對象,然后將這些對象回收,回收后的狀態如圖1.3。
回收前狀態 圖1.2回收后狀態 圖1.3標記-清除算法主要有兩個不足:一個是效率問題, 標記和清除兩個過程的效率都不高;另一個是空間問題,標記清除之后會產生大量不連續的內存碎片,空間碎片太多可能會導致以后在程序運行過程中需要分配較大對象時,無法找到足夠的連續內存而不得不提前觸發另一次垃圾收集動作。
二、復制算法(Copying)
復制算法將可用內存容量劃分為大小相等的兩塊,每次只使用其中的一塊。當這一塊的內存用完了,就將還存活著的對象復制到另外一塊上面,然后再把已使用過的這一塊的內存空間全部清理掉。這樣使得每次GC是對整半個內存區域進行回收,內存分配時也就不用考慮內存碎片等問題,只要移動堆指針,按順序分配內存即可。這種方式實現簡單,運行高效。但是這種算法的代價是將內存縮小為原來的一半,未免太高了一點。復制算法的執行過程如圖1.4與圖1.5所示。
回收前狀態 圖1.4回收后狀態 圖1.5三、標記-整理算法(Mark-Compact)
標記-整理算法,標記過程與標記-清除算法一樣,但后續步驟不是直接對可回收對象進行清理,而是讓所有存活的對象都向一端移動, 然后直接清理掉端邊界以外的內存,“標記-整理”算法的過程如圖1.6與圖1.7所示。
回收前狀態 圖1.6回收后狀態 圖1.7四、分代收集算法(Generational Colllection)
當前主流虛機的垃圾收集都采用“分代收集”,這種算法并沒有什么新的思想,只是根據對象存活周期的不同將內存劃分為幾塊。一般是把JAVA堆分為新生代和老年代(新生代與老年代后續會有文章介紹),這樣就可以根據各個年代的特點采用最適當的收集算法。在新生代中,每次垃圾收集時都發現有大批對象死去,只有少量存活,那就選用復制算法,只需要付出少量存活對象的復制成本就可以完成收集。而老年代中因為對象存活率高、所以使用“標記-清除”或者“標記-整理” 算法來進行回收。
更多文章可關注微信公眾號:IT雞窩
總結
以上是生活随笔為你收集整理的jvm垃圾回收机制_干货|JVM垃圾回收机制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python如何改变入参的值_从事数据分
- 下一篇: oracle 作业已存在,ORA-316