1. 程式人生 > >深入理解JVM(一)——JVM記憶體模型

深入理解JVM(一)——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在不斷調整大小。

程式計數器

這裡記錄了執行緒執行的位元組碼的行號,在分支、迴圈、跳轉、異常、執行緒恢復等都依賴這個計數器。

方法區

型別資訊、欄位資訊、方法資訊、其他資訊

總結

名稱特徵作用配置異常
棧區執行緒私有,使用一段連續的記憶體空間存放區域性變量表、操作棧、動態連結、方法出口-XSsStackOverflowError OutOfMemoryError
執行緒共享,生命週期與虛擬機器相同儲存物件例項-Xms -Xmx -XmnOutOfMemoryError
程式計數器執行緒私有、佔用記憶體小位元組碼行號
方法區執行緒共享儲存類載入資訊、常量、靜態變數等-XX:PermSize -XX:MaxPermSizeOutOfMemoryError

垃圾回收

如何定義垃圾

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

判斷物件可以回收的情況:

  • 顯示的把某個引用置位NULL或者指向別的物件
  • 區域性引用指向的物件
  • 弱引用關聯的物件

垃圾回收的方法

Mark-Sweep標記-清除演算法

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

Copying複製演算法

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

Mark-Compact標記-整理演算法

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

Generational Collection 分代收集

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

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

  • 新生代(Young Generation):用於存放新建立的物件,採用複製回收方法,如果在s0和s1之間複製一定次數後,轉移到年老代中。這裡的垃圾回收叫做minor GC;
  • 年老代(Old Generation):這些物件垃圾回收的頻率較低,採用的標記整理方法,這裡的垃圾回收叫做 major GC。
  • 永久代(Permanent Generation):存放Java本身的一些資料,當類不再使用時,也會被回收。

這裡可以詳細的說一下新生代複製回收的演算法流程:

在新生代中,分為三個區: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

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

參考

    https://blog.csdn.net/u010425776/article/details/51170118