java垃圾回收機制的理解


Java垃圾回收機制算法

  1. 標記----清除算法
  2. 復制算法
  3. 標記----整理算法
  4. 分代收集算法

為什么要進行垃圾回收

  因為當一個對象的引用不可達,或者一個對象沒有任何引用指向它,那么它就沒有必要在內存中繼續存在,此時它就處於可以被GC(垃圾回收器)回收的對象,jvm虛擬機動態的收集不可用的對象,達到釋放內存的目的。

垃圾回收區域

     通常情況下的jvm虛擬機把內存都分為了如下幾塊

  1. 虛擬機棧(生命周期和線程相同,每一個線程執行的時候會創建一個棧幀用於存儲局部變量表,操作數棧,動態鏈接,方法出入口等信息,每一個方法從調用到執行完成的過程,就對應一個棧幀在虛擬機中入棧到出棧的過程,局部變量表存儲了8大基本數據類型和對象的引用。會拋出OutOfMemoryError錯誤)
  2. 本地方法棧(主要為虛擬機使用到的native方法服務,會拋出OutOfMemoryError和StackOverflowError錯誤)
  3. 方法區(線程共有的,運行時常量池也屬於方法區,用於存儲被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯后的代碼等數據,別名為Non-Heap,也是GC分代收集擴展的區。)
  4. 堆(GC堆,存儲new出來對象,Java管理的最大的一塊內存,)
  5. 程序計數器(線程私有的,會拋出OutOfMemoryError)

其中虛擬機棧和本地方法棧在某些虛擬機中(例如sun的HotSpot虛擬機中)統稱為虛擬機棧,並且虛擬機棧和程序計數器都是線程私有的。

四種垃圾收集算法介紹

  1. 標記----清除算法:分為標記和清除兩個階段,首先標記出所有需要回收的對象,在標記完成后統一回收被標記的對象。這種算法有兩個不足的地方,一個是效率問題,標記和清除兩個過程效率都不高,另一個是空間問題,標記清除之后會產生大量不連續的內存碎片,空間碎片過多可能會導致以后程序運行過程中需要分配較大對象時,無法找到足夠連續的內存而不得不提前觸發另一次垃圾收集動作。
  2. 復制算法:為了解決效率問題,出現了復制算法,這種算法把內存分為大小相等的兩塊,每次只是用其中的一塊。當這一塊內存用完了,就將還存活的對象復制到另一塊上面,然后把已經使用過的那一塊內存整個清理掉,這樣使得每次清理的只是半個內存區域,內存分配時就不用考慮內存碎片等復雜的情況,只要移動堆頂的指針,按順序分配內存即可,實現簡單,運行高效,但是缺點是,把內存縮小為原來的一半,代價有點高。目前商業虛擬機都采用這種收集算法來回收新生代,不過內存並不是按1:1這樣的比例划分的,而是將內存分為較大的Eden空間和兩塊較小的Survivor空間,每次只使用Eden和其中的一塊Survivor區,當回收時,將Eden和survivor區中還存活的對象復制到另一個Survivor區中,最后清理掉Eden和Survivor空間。
  3. 標記----整理算法:和標記清除算法類似,只不過后續步驟不是直接對可回收對象進行清理,而是讓存活的對象都向一端移動,然后直接清理到邊界以外的內存空間。
  4. 分代收集算法:當前商業虛擬機的垃圾收集都采用分代收集算法,根據對象存活周期的不同將內存划分為幾塊,一般把堆划分為新生代和老年代,這樣就可以各個年代的特點采用最適當的收集算法。在新生代中,每次垃圾收集時都發現大批對象死去,只有少量存活,就選用復制算法,只需要付出少量存活對象的復制成本就可以完成收集,而老年代中對象存活率高,就必須使用標記----清理或者標記----整理算法進行回收。

名詞解析:

Minor GC:新生代收集
Major GC:老年代收集
Full GC:全收集
Mixed GC:混合收集,收集整個年輕代和部分老年代,目前只有G1收集器會使用此收集器
stop the world:暫停所有用戶線程,表現為應用失去響應
 

查看當前jdk使用的垃圾收集器

java -XX:+PrintCommandLineFlags -version

 

建議:

  我們在寫程序的時候,應當避免頻繁出現大對象,因為經常出現大對象容易導致內存空間還有不少空間時就提前觸發垃圾收集以獲取足夠的連續空間來存放這些大對象。最典型的大對象為很長的字符串以及數組。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM