在上一篇博客中講GC算法的時候提到了一些關於JVM內存模型.JVM中用heap堆來存儲運行時的數據,所有類實例和數組由堆分配內存,JVM啓動時創建堆(heap memory),在堆以外的內存叫非堆(non-heap memory)
1.堆(Heap space)
在JVM的堆內存空間中,從大的層面劃分,可以分爲新生代(Young)和老年代空間(Old).其中Young空間又被分爲兩個部分和3個板塊,分別爲1個Egen區和2個survivor區.
Minor GC
從年輕代空間(包括Egen和survivor區域)回收內存被稱爲Minor GC.每次Minor GC會清理年輕代的內存.
Eden區域:
是用來存放使用new或者newInstance等方式創建的對象,默認都是存放在Eden區,除非這個對象太大,或者超過了設定的閾值-XX:PretenureSizeThresold,這樣的對象會被直接分配到Old區域。
Survivor(倖存)區
一般稱S0,S1,理論上他們是一樣大的,解釋一下,他們是如何工作的: 在不斷創建對象的過程中,Eden區會滿,這時候會開始做Young G也叫Minor GC,而Young空間的第一次GC就是找出Eden區中,倖存活着的對象,然後將這些對象,放到S0,或S1區中的其中一個, 假設第一次選擇了S0,它會逐步將活着的對象拷貝到S0區域,但是如果S0區域滿了,剩下活着的對象只能放old區域了,接下來要做的是,將Eden區域
清空,此時時候S1區域也是空的。
當第二次Eden區域滿的時候,就將Eden區域中活着的對象+S0區域中活着的對象,遷移到S1中,如果S1放不下,就會將剩下的部門,放到Old區域中,只是這次對象來源區域增加了S0,最後會將Eden區+S0區域,清空
第三次和第四次依次類推,始終保證S0和S1有一個是空的,用來存儲臨時對象,用於交換空間的目的,反反覆覆多次沒有被淘汰的對象,將會放入old區域中,默認是15次,計數器會在對象的頭部記錄它交換的次數。
老年代(Old)
用於存放經過多次新生代GC仍然存活的對象。新建的對象也可能直接進入老年代,比如大對象(可通過參數指定)和大的數組對象。
永恆代(Perment)
存放類的Meta信息。
Major GC
是清理老年代.
Full GC
是清理整個堆空間---包括年輕代和老年代.
發生在老年代的GC,當老年代沒有足夠的空間時即發生Full GC.在這裏可能會發生Stop-The-World,這是java中一種全局暫停的現象,所有java代碼停止,native代碼可以執行,但不能和JVM交互.多半由於GC引起:Dump線程;死鎖檢查;堆Dump.
2.方法區:
用來儲存已經加載的類信息,常量,靜態變量以及方法代碼.
3.Java虛擬機棧
也叫棧區。是由一個個棧幀組成的後進先出的棧式結構,棧幀中存放方法運行時的局部變量、方法出口等信息。當調用一個方法時,就會在虛擬機棧中創建一個棧幀用於存放這些數據,方法調用完時棧幀消失。若方法中又調用了其他方法,則繼續在棧頂創建新的棧.
4.本地方法棧
與虛擬機棧類似,區別是本地方法棧是爲Native方法服務的,而java虛擬機棧是爲java方法服務的.
5.程序計數器
最小的一塊內存,通過改變計數器的值來選取下一條需要執行的字節碼指令.程序計數器用來爲線程獨立擁有,線互補互補影響,保證線程切換後能準確恢復到執行位置,線程執行指令的跳轉、循環、分支都要依賴計數器來完成.