JVM堆記憶體詳解

2022-09-19 04:42:11 字數 2559 閱讀 8205

j**a堆記憶體管理是影響效能主要因素之一。

堆記憶體溢位是j**a專案非常常見的故障,在解決該問題之前,必須先了解下j**a堆記憶體是怎麼工作的。

先看下j**a堆記憶體是如何劃分的,如圖:

jvm記憶體劃分為堆記憶體和非堆記憶體,堆記憶體分為年輕代(young generation)、老年代(old generation),非堆記憶體就乙個永久代(permanent generation)。

年輕代又分為eden和survivor區。survivor區由fromspace和tospace組成。eden區佔大容量,survivor兩個區佔小容量,預設比例是8:1:1。

堆記憶體用途:存放的是物件,垃圾收集器就是收集這些物件,然後根據gc演算法**。

非堆記憶體用途:永久代,也稱為方法區,儲存程式執行時長期存活的物件,比如類的元資料、方法、常量、屬性等。

在jdk1.8版本廢棄了永久代,替代的是元空間(metaspace),元空間與永久代上類似,都是方法區的實現,他們最大區別是:元空間並不在jvm中,而是使用本地記憶體。

元空間有注意有兩個引數:

移除永久代原因:為融合hotspot jvm與jrockit vm(新jvm技術)而做出的改變,因為jrockit沒有永久代。

有了元空間就不再會出現永久代oom問題了!

新生成的物件首先放到年輕代eden區,當eden空間滿了,觸發minor gc,存活下來的物件移動到survivor0區,survivor0區滿後觸發執行minor gc,survivor0區存活物件移動到suvivor1區,這樣保證了一段時間內總有乙個survivor區為空。經過多次minor gc仍然存活的物件移動到老年代。

老年代儲存長期存活的物件,佔滿時會觸發major gc=full gc,gc期間會停止所有執行緒等待gc完成,所以對響應要求高的應用儘量減少發生major gc,避免響應超時。

minor gc : 清理年輕代

major gc : 清理老年代

full gc : 清理整個堆空間,包括年輕代和永久代

所有gc都會停止應用所有執行緒。

將物件根據存活概率進行分類,對存活時間長的物件,放到固定區,從而減少掃瞄垃圾時間及gc頻率。針對分類進行不同的垃圾**演算法,對演算法揚長避短。

主要為了解決碎片化。如果記憶體碎片化嚴重,也就是兩個物件占用不連續的記憶體,已有的連續記憶體不夠新物件存放,就會觸發gc。

引數描述

-xms

堆記憶體初始大小,單位m、g

-xmx(maxheapsize)

堆記憶體最大允許大小,一般不要大於物理記憶體的80%

-xx:permsize

非堆記憶體初始大小,一般應用設定初始化200m,最大1024m就夠了

-xx:maxpermsize

非堆記憶體最大允許大小

-xx:newsize(-xns)

年輕代記憶體初始大小

-xx:maxnewsize(-xmn)

年輕代記憶體最大允許大小,也可以縮寫

-xx:survivorratio=8

年輕代中eden區與survivor區的容量比例值,預設為8,即8:1

-xss

堆疊記憶體大小

紅色是標記的非活動物件,綠色是活動物件。

gc分為兩個階段,標記和清除。首先標記所有可**的物件,在標記完成後統一**所有被標記的物件。同時會產生不連續的記憶體碎片。碎片過多會導致以後程式執行時需要分配較大物件時,無法找到足夠的連續記憶體,而不得已再次觸發gc。

將記憶體按容量劃分為兩塊,每次只使用其中一塊。當這一塊記憶體用完了,就將存活的物件複製到另一塊上,然後再把已使用的記憶體空間一次清理掉。這樣使得每次都是對半個記憶體區**,也不用考慮記憶體碎片問題,簡單高效。缺點需要兩倍的記憶體空間。

也分為兩個階段,首先標記可**的物件,再將存活的物件都向一端移動,然後清理掉邊界以外的記憶體。此方法避免標記-清除演算法的碎片問題,同時也避免了複製演算法的空間問題。

一般年輕代中執行gc後,會有少量的物件存活,就會選用複製演算法,只要付出少量的存活物件複製成本就可以完成收集。而老年代中因為物件存活率高,沒有額外過多記憶體空間分配,就需要使用標記-清理或者標記-整理演算法來進行**。

cms收集器是縮短暫停應用實踐為目標而設計的,是基於標記清楚演算法實現,整個過程分為4個步驟:

其中,初始標記、重新標記這兩個步驟仍然需要暫停應用執行緒、初始標記只是標記一下gc roots能直接關聯到的物件,速度很快,併發標記階段是標記可**物件,而重新標記階段則是為了修正併發標記期間因使用者程式繼續執行導致標記成聖變動的那一部分物件的標記記錄,這個階段暫停時間比標記階段稍長一點,但遠比併發標記的時間短。

由於整個過程消耗最長的併發標記和併發清楚過程收集器執行緒都可以與使用者執行緒一起工作,所以,cms收集器記憶體**與使用者一起併發執行嗎,大大減少了暫停時間。

暫時學習到這裡,不想複製讚貼

**自:

JVM堆記憶體調優

堆大小設定 jvm 中最大堆大小有三方面限制 相關作業系統的資料模型 32 bt還是64 bit 限制 系統的可用虛擬記憶體限制 系統的可用物理記憶體限制。32位系統下,一般限制在1.5g 2g 64為作業系統對記憶體無限制。我在windows server 2003 系統,3.5g物理記憶體,jd...

jvm堆記憶體的資料共享

以前沒學jvm的時候,老師總是講在堆記憶體中的資料是共享的,多個執行緒可以使用堆中的同乙個資料,於是才會有加鎖的操作。其實,堆裡的資料就是是共享的 那麼tlab是怎麼一回事呢?首先物件分配時,現在當前執行緒中的tlab中檢視空間是否有多餘,如果有,則分配到此執行緒中的tlab中。1.tlab是在堆記...

堆記憶體棧記憶體詳解

堆 順序隨意 heap 和資料結構中的堆完全兩回事,記憶體分配的操作方式類似於鍊錶 棧 先進後出 stack 和資料結構中的棧也不是一回事,但是記憶體分配的操作方式類似於資料結構中的棧 入口出口為同乙個 此文討論的是 作業系統中的堆和棧,而不是資料結構中的堆和棧 堆和棧的區別 一 預備知識 程式的記...