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 |
如何定義垃圾
有兩種方式,一種是引用計數(但是無法解決循環引用的問題);另一種就是可達性分析。
判斷對象可以回收的情況:
- 顯示的把某個引用置位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
大緻的流程為:初始标記--并發标記--最終标記--篩選回收
參考
- JVM記憶體模型:http://developer.51cto.com/art/200911/165015.htm
- 垃圾回收:http://www.importnew.com/19085.html
- JVM垃圾回收器:http://www.cnblogs.com/chengxuyuanzhilu/p/7088316.html
- 記憶體模型: http://blog.csdn.net/u012152619/article/details/46968883
作者:xingoo
出處:http://www.cnblogs.com/xing901022
本文版權歸作者和部落格園共有。歡迎轉載,但必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接!