JVM堆記憶體詳解,你有過迷茫嗎
-
JVM記憶體劃分為堆記憶體和非堆記憶體,堆記憶體分為年輕代(Young Generation)、老年代(Old Generation),非堆記憶體就一個永久代(Permanent Generation)。
-
年輕代又分為Eden和Survivor區。Survivor區由FromSpace和ToSpace組成。Eden區佔大容量,Survivor兩個區佔小容量,預設比例是8:1:1。
-
堆記憶體用途:存放的是物件,垃圾收集器就是收集這些物件,然後根據GC演算法回收。
-
非堆記憶體用途:永久代,也稱為方法區,儲存程式執行時長期存活的物件,比如類的元資料、方法、常量、屬性等。
在JDK1.8版本廢棄了永久代,替代的是元空間(MetaSpace),元空間與永久代上類似,都是方法區的實現,他們最大區別是:元空間並不在JVM中,而是使用本地記憶體。
元空間有注意有兩個引數:
-
MetaspaceSize :初始化元空間大小,控制發生GC閾值
-
MaxMetaspaceSize : 限制元空間大小上限,防止異常佔用過多實體記憶體
二、為什麼移除永久代?
移除永久代原因:為融合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頻率。針對分類進行不同的垃圾回收演算法,對演算法揚長避短。
五、為什麼survivor分為兩塊相等大小的倖存空間?
主要為了解決碎片化。如果記憶體碎片化嚴重,也就是兩個物件佔用不連續的記憶體,已有的連續記憶體不夠新物件存放,就會觸發GC。
六、JVM堆記憶體常用引數
| 引數 | 描述 |
| --- | --- |
| -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,Garbage Collection)
紅色是標記的非活動物件,綠色是活動物件。
1、標記-清除(Mark-Sweep)
GC分為兩個階段,標記和清除。首先標記所有可回收的物件,在標記完成後統一回收所有被標記的物件。同時會產生不連續的記憶體碎片。碎片過多會導致以後程式執行時需要分配較大物件時,無法找到足夠的連續記憶體,而不得已再次觸發GC。
2、複製(Copy)
總結
雖然我個人也經常自嘲,十年之後要去成為外賣專員,但實際上依靠自身的努力,是能夠減少三十五歲之後的焦慮的,畢竟好的架構師並不多。
架構師,是我們大部分技術人的職業目標,一名好的架構師來源於機遇(公司)、個人努力(吃得苦、肯鑽研)、天分(真的熱愛)的三者協作的結果,實踐+機遇+努力才能助你成為優秀的架構師。
如果你也想成為一名好的架構師,那或許這份Java成長筆記你需要閱讀閱讀,希望能夠對你的職業發展有所幫助。