天天看點

JVM優化:堆

一、Java 堆概念

1、簡介

對于Java應用程式來說, Java堆(Java Heap) 是虛拟機所管理的記憶體中最大的一塊。 Java堆是被所 有線程共享 的一塊記憶體區域, 在虛拟機啟動時建立。 此記憶體區域的唯一目的就是存放對象執行個體, Java 世界裡“幾乎”所有的對象執行個體都在這裡配置設定記憶體。“幾乎”是指從實作角度來看, 随着Java語 言的發展, 現在已經能看到些許迹象表明日 後可能出現值類型的支援, 即使隻考慮現在, 由于即時編譯技術的進步, 尤其是逃逸分析技術的日漸強大, 棧上 配置設定、 标量替換優化手段已經導緻一些微妙的變化悄然發生, 是以說Java對象執行個體都配置設定在堆上也漸漸變得不是 那麼絕對了。

JVM優化:堆

2、堆的特點

(1)是Java虛拟機所管理的記憶體中最大的一塊。

(2)堆是jvm所有線程共享的。 堆中也包含私有的線程緩沖區 Thread Local Allocation Buffer (TLAB)

(3)在虛拟機啟動的時候建立。

(4)唯一目的就是存放對象執行個體,幾乎所有的對象執行個體以及數組都要在這裡配置設定記憶體。 (5)Java堆是垃圾收集器管理的主要區域。

(6)是以很多時候java堆也被稱為“GC堆”(Garbage Collected Heap)。從記憶體回收的角度來看,由于現在收集器 基本都采用分代收集算法,是以Java堆還可以細分為:新生代和老年代;新生代又可以分為:Eden 空間、From Survivor空間、To Survivor空間。

(7)java堆是計算機實體存儲上不連續的、邏輯上是連續的,也是大小可調節的(通過-Xms和-Xmx控制)。

(8)方法結束後,堆中對象不會馬上移出僅僅在垃圾回收的時候時候才移除。

(9)如果在堆中沒有記憶體完成執行個體的配置設定,并且堆也無法再擴充時,将會抛出OutOfMemoryError異常

3、設定堆空間大小

1. 記憶體大小-Xmx/-Xms

使用示例: -Xmx20m -Xms5m

說明: 當下Java應用最大可用記憶體為20M, 最小記憶體為5M

total Memory和最大的記憶體之間還是存在一定 差異的,就是說JVM一般會盡量保持記憶體在一個盡可能低的層面,而非貪婪做法按照最大的記憶體來進行配置設定。

其實JVM在配置設定記憶體過 程中是動态的, 按需來配置設定的。

4、堆的分類

現在垃圾回收器都使用分代理論,堆空間也分類如下:

在Java7 Hotspot虛拟機中将Java堆記憶體分為3個部分:

  • 青年代Young Generation
  • 老年代Old Generation
  • 永久代Permanent Generation
JVM優化:堆

在Java8以後,由于方法區的記憶體不再配置設定在Java堆上,而是存儲于本地記憶體元空間Metaspace中,是以永久代就不 存在了,在幾天前(2018年9約25日)Java11正式釋出以後,我從官網上找到了關于Java11中垃圾收集器的官方文檔, 文檔中沒有提到“永久代”,而隻有青年代和老年代。

JVM優化:堆

二、年輕代和老年代

1.JVM中存儲java對象可以被分為兩類:

1)年輕代(Young Gen):年輕代主要存放新建立的對象,記憶體大小相對會比較小,垃圾回收會比較頻繁。年輕代分 成1個Eden Space和2個Suvivor Space(from 和to)。

2)年老代(Tenured Gen):年老代主要存放JVM認為生命周期比較長的對象(經過幾次的Young Gen的垃圾回收後仍 然存在),記憶體大小相對會比較大,垃圾回收也相對沒有那麼頻繁。

2.配置新生代和老年代堆結構占比

預設 -XX:NewRatio=2 , 辨別新生代占1 , 老年代占2 ,新生代占整個堆的1/3

修改占比 -XX:NewPatio=4 , 辨別新生代占1 , 老年代占4 , 新生代占整個堆的1/5

Eden空間和另外兩個Survivor空間占比分别為8:1:1

可以通過操作選項 -XX:SurvivorRatio 調整這個空間比例。 比如 -XX:SurvivorRatio=8 幾乎所有的java對象都在Eden區建立, 但80%的對象生命周期都很短,建立出來就會被銷毀

JVM優化:堆

從圖中可以看出: 堆大小 = 新生代 + 老年代。其中,堆的大小可以通過參數 –Xms、-Xmx 來指定。

預設的,新生代 ( Young ) 與老年代 ( Old ) 的比例的值為 1:2 ( 該值可以通過參數 –XX:NewRatio 來指定 ),即:新生 代 ( Young ) = 1/3 的堆空間大小。老年代 ( Old ) = 2/3 的堆空間大小。其中,新生代 ( Young ) 被細分為 Eden 和 兩個 Survivor 區域,這兩個 Survivor 區域分别被命名為 from 和 to,以示區分。 預設的,Edem : from : to = 8 : 1 : 1 ( 可以 通過參數 –XX:SurvivorRatio 來設定 ),即: Eden = 8/10 的新生代空間大小,from = to = 1/10 的新生代空間大小。 JVM 每次隻會使用 Eden 和其中的一塊 Survivor 區域來為對象服務,是以無論什麼時候,總是有一塊 Survivor 區域 是空閑着的。是以,新生代實際可用的記憶體空間為 9/10 ( 即90% )的新生代空間。

三、對象配置設定過程

JVM設計者不僅需要考慮到記憶體如何配置設定,在哪裡配置設定等問題,并且由于記憶體配置設定算法與記憶體回收算法密切相關, 是以還需要考慮GC執行完記憶體回收後是否存在空間中間産生記憶體碎片。

配置設定過程

1.new的對象先放在伊甸園區。該區域有大小限制

2.當伊甸園區域填滿時,程式又需要建立對象,JVM的垃圾回收器将對伊甸園預期進行垃圾回收(Minor GC),将伊 甸園區域中不再被其他對象引用的額對象進行銷毀,再加載新的對象放到伊甸園區

3.然後将伊甸園區中的剩餘對象移動到幸存者0區

4.如果再次觸發垃圾回收,此時上次幸存下來的放在幸存者0區的,如果沒有回收,就會放到幸存者1區

5.如果再次經曆垃圾回收,此時會重新傳回幸存者0區,接着再去幸存者1區。

6.如果累計次數到達預設的15次,這會進入養老區。 可以通過設定參數,調整門檻值 -XX:MaxTenuringThreshold=N

7.養老區記憶體不足是,會再次出發GC:Major GC 進行養老區的記憶體清理

8.如果養老區執行了Major GC後仍然沒有辦法進行對象的儲存,就會報OOM異常

JVM優化:堆
JVM優化:堆
JVM優化:堆

配置設定對象流程