程序猿的日常——JVM內存模型與垃圾回收


Java開發有個很基礎的問題,雖然我們平時接觸的不多,但是了解它卻成為Java開發的必備基礎——這就是JVM。在C++中我們需要手動申請內存然后釋放內存,否則就會出現對象已經不再使用內存卻仍被占用的情況。在Java中JVM內置了垃圾回收的機制,幫助開發者承擔對象的創建和釋放的工作,極大的減輕了開發的負擔。那是不是我們就不需要了解JVM了,顯然在做一些優化或者深入研究應用性能的時候,JVM還是起了很關鍵的作用的。因此本篇就總結性的描述下JVM的內存模型與垃圾回收相關的知識。

本文的主要內容如下:

  • 內存模型
  • 垃圾回收
  • 參考文章

內存模型

各部分的功能

這幾個存儲區最主要的就是棧區和堆區,那么什么是棧什么是堆呢?說的簡單點,棧里面存放的是基本的數據類型和引用,而堆里面則是存放各種對象實例的。

堆與棧分開設計是為什么呢?

  • 棧存儲了處理邏輯、堆存儲了具體的數據,這樣隔離設計更為清晰
  • 堆與棧分離,使得堆可以被多個棧共享。
  • 棧保存了上下文的信息,因此只能向上增長;而堆是動態分配

棧的大小可以通過-XSs設置,如果不足的話,會引起java.lang.StackOverflowError的異常

棧區

線程私有,生命周期與線程相同。每個方法執行的時候都會創建一個棧幀(stack frame)用於存放 局部變量表、操作棧、動態鏈接、方法出口。

存放對象實例,所有的對象的內存都在這里分配。垃圾回收主要就是作用於這里的。

  • 堆得內存由-Xms指定,默認是物理內存的1/64;最大的內存由-Xmx指定,默認是物理內存的1/4。
  • 默認空余的堆內存小於40%時,就會增大,直到-Xmx設置的內存。具體的比例可以由-XX:MinHeapFreeRatio指定
  • 空余的內存大於70%時,就會減少內存,直到-Xms設置的大小。具體由-XX:MaxHeapFreeRatio指定。

因此一般都建議把這兩個參數設置成一樣大,可以避免JVM在不斷調整大小。

程序計數器

這里記錄了線程執行的字節碼的行號,在分支、循環、跳轉、異常、線程恢復等都依賴這個計數器。

方法區

類型信息、字段信息、方法信息、其他信息

總結

名稱 特征 作用 配置 異常
棧區 線程私有,使用一段連續的內存空間 存放局部變量表、操作棧、動態鏈接、方法出口 -XSs StackOverflowError OutOfMemoryError
線程共享,生命周期與虛擬機相同 保存對象實例 -Xms -Xmx -Xmn OutOfMemoryError
程序計數器 線程私有、占用內存小 字節碼行號
方法區 線程共享 存儲類加載信息、常量、靜態變量等 -XX:PermSize -XX:MaxPermSize OutOfMemoryError

垃圾回收

如何定義垃圾

有兩種方式,一種是引用計數(但是無法解決循環引用的問題);另一種就是可達性分析。

判斷對象可以回收的情況:

  • 顯示的把某個引用置位NULL或者指向別的對象
  • 局部引用指向的對象
  • 弱引用關聯的對象

垃圾回收的方法

Mark-Sweep標記-清除算法

這種方法優點就是減少停頓時間,但是缺點是會造成內存碎片。

Copying復制算法

這種方法不涉及到對象的刪除,只是把可用的對象從一個地方拷貝到另一個地方,因此適合大量對象回收的場景,比如新生代的回收。

Mark-Compact標記-整理算法

這種方法可以解決內存碎片問題,但是會增加停頓時間。

Generational Collection 分代收集

最后的這種方法是前面幾種的合體,即目前JVM主要采取的一種方法,思想就是把JVM分成不同的區域。每種區域使用不同的垃圾回收方法。

上面可以看到堆分成兩個個區域:

  • 新生代(Young Generation):用於存放新創建的對象,采用復制回收方法,如果在s0和s1之間復制一定次數后,轉移到年老代中。這里的垃圾回收叫做minor GC;
  • 年老代(Old Generation):這些對象垃圾回收的頻率較低,采用的標記整理方法,這里的垃圾回收叫做 major GC。

這里可以詳細的說一下新生代復制回收的算法流程:

在新生代中,分為三個區:Eden, from survivor, to survior。

  • 當觸發minor GC時,會先把Eden中存活的對象復制到to Survivor中;
  • 然后再看from survivor,如果次數達到年老代的標准,就復制到年老代中;如果沒有達到則復制到to survivor中,如果to survivor滿了,則復制到年老代中。
  • 然后調換from survivor 和 to survivor的名字,保證每次to survivor都是空的等待對象復制到那里的。

垃圾回收器

串行收集器 Serial

這種收集器就是以單線程的方式收集,垃圾回收的時候其他線程也不能工作。

並行收集器 Parallel

以多線程的方式進行收集

並發標記清除收集器 Concurrent Mark Sweep Collector, CMS

大致的流程為:初始標記--並發標記--重新標記--並發清除

G1收集器 Garbage First Collector

大致的流程為:初始標記--並發標記--最終標記--篩選回收

參考


免責聲明!

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



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