JVM(和Spark)性能優化:使用Java Mission Control (7)
Java垃圾回收器是一種“自適應的、分代的、停止-復制、標記-清掃”式的垃圾回收器。在基于分代的內存回收策略中,堆空間通常都被劃分為3個代,年輕代,年老代(或者tenured代-終身代),永生代。在年輕代中又被劃分為三個小的區域,分別為:Eden(伊甸)區,S0區(survivor 0),S1區(survivor 1),如下圖所示:

其中,新的對象總被分配到年輕代中,當年輕代空間被填滿時,這時需要執行一次垃圾回收,即執行 minor GC,回收不再被引用的對象,并同時提升幸存的對象其年齡,年輕代中的幸存對象都有年齡標識字段,一旦其達到一定的閾值,則仍然幸存的對象將被提升到年老代空間中。
年老代的空間用于存放長時間幸存的對象,即生命周期較長的對象,一旦年輕代空間的幸存對象達到一定的年齡閾值后,將被自動提升到年老代,當年老代空間被對象填滿(達到限額)時,這時執行一次Major GC。相較于minor GC, Major GC的執行次數要比minor GC要少很多,同時,Major Gc 執行的時間較Minor Gc要長。因為其涉及到更多的對象掃描。這種分代的思想,也是基于在實踐中,對于新分配的對象具有更短的生命周期,年老的對象具有更長的生命周期所作出的較佳的選擇。
與此同時,Minor Gc 和 Major Gc 在執行垃圾收集時,采取的是stop the world (STW) ,即終止正在運行的線程,等GC執行完畢在恢復所有的線程。
JVM在Old區申請不到內存,會進行Full GC。對于永生代的內存,主要是用來存放元數據的相關信息,類及其方法的信息。當一個類不再使用時將會被回收,當執行Full GC時,將會掃描永生代內存,對其進行垃圾回收。
采用復制收集器(Copying)。
一般情況下,當新對象生成,并且在Eden申請空間失敗時,就會觸發Scavenge GC,對Eden區域進行GC,清除非存活對象,并且把尚且存活的對象移動到Survivor區。然后整理Survivor的兩個區。這種方式的GC是對年輕代的Eden區進行,不會影響到年老代。因為大部分對象都是從Eden區開始的,同時Eden區不會分配的很大,所以Eden區的GC會頻繁進行。因而,一般在這里需要使用速度快、效率高的算法,使Eden去能盡快空閑出來。
采用標記-整理收集器(Mark-Compact)。
對整個堆進行整理,包括Young、Tenured和Perm。Full GC因為需要對整個對進行回收,所以比Scavenge GC要慢,因此應該盡可能減少Full GC的次數。在對JVM調優的過程中,很大一部分工作就是對于FullGC的調節。有如下原因可能導致Full GC:
年老代(Tenured)被寫滿(達到限額)
永生代(Perm)被寫滿
System.gc()被顯示調用
上一次GC之后,Heap的各域分配策略有變更
注:Minor GC=Young GC= Scavenge GC,Major GC≈Full GC,參見《Java性能優化權威指南》第4章和這個博客
Java G1 GC 是分區的(regionalized)、分代的,它把堆heap切分為多個大小相等的區塊regions,這個區塊的大小可以從1 MB到32 MB,但總數不會超過2048個區塊。eden, survivor,和 old generations 是這些區塊的邏輯集合logical sets且不是連續的。
看起來像這種樣子:
下圖是HotSpot的幾種收集器(不含G1):
性能優化的三個指標:吞吐量、延遲、內存占用。
JVM垃圾收集三個基本原則:
? Minor GC最多原則
? GC內存最大化原則
? GC調優的3選2原則
Oracle官方建議,heap大于16GB,就用G1垃圾收集器!替換掉Parallel Collector(默認的)和CMS Collector的長時暫停“Stop The World”。【注:基本上確定了在Java 9中G1將是默認的GC了。】G1不要設置年輕代的大小-Xmn。
The Garbage First Garbage Collector (G1 GC) is the low-pause, server-style generational garbage collector
? G1 GC uses concurrent and parallel phases to achieve its target:pause time and to maintain good throughput
? When G1 GC determines that a garbage collection is necessary, it collects the regions with the least live data first (garbage first)
JVM的長時暫停應用程序,可能會導致網絡ack超時或executor lost。可以嘗試下如下的優化設置選項:
-XX:+UseG1GC
-XX:MaxGCPauseMillis=150~500
-XX:GCPauseIntervalMillis=200
-XX:ParallelGCThreads=8 + ((N - 8) * 5 / 8)
-XX:ConcGCThreads= {ParallelGCThreads} / 4
-XX:+ParallelRefProcEnabled
-XX:-ResizePLAB
-XX:+UnlockExperimentalVMOptions -XX:G1MaxNewSizePercent=75 -XX:G1NewSizePercent=3 //如果heap>100GB,則設為1
更多的G1細節參看官方文檔:http://www.oracle.com/technetwork/articles/java/g1gc-1984535.html
注意,在Java 8中永生代PermGen已經被刪除了,取而代之的是Metaspace用來保存類的元數據,它位于本地(native)內存,而不是堆上。PermSize 和 MaxPermSize選項相應也從JDK中刪除了。但可以通過如下參數控制non-heap內存的最大值:
-XX:ReservedCodeCacheSize=100m
-XX:MaxMetaspaceSize=128m
-XX:CompressedClassSpaceSize=128m
Java 8中的G1,引入了一個強大的優化,字符串去重,因為String和它內部的char[]常常占用非常大的堆空間。G1就會識別出相同的字符串,并把指針指向同一個內部char[],從而避免相同字符串的多個副本在堆上。需要加上:
-XX:+UseStringDeduplication
Oracle官方也建議,當heap小于等于32GB時,也可以試試CMS垃圾收集器的優化配置:
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC
-XX:+UseIncrementalMode
-XX:+UseIncrementalPacing
-XX:CMSInitiatingOccupancyFraction=70 //如果程序中維持了一個很大的長命對象的緩存,則可以加大此值為90
-XX:+CMSParallelRemarkEnabled
-XX:+UseParallelGC
-XX:+UseParallelOldGC
-XX:ParallelGCThreads=20
這些參數選項需要根據具體的業務不斷的試驗并測量,直到找到最合適的數值。觀察GC中的年輕代、年老代的大小隨GC的變化,適當調整試驗不同代的大小。有人說,無測量無改進。有了JMC/JFR,就變得容易多了。
GC日志樣例1 ,Minor GC :
GC日志樣例2,Full GC:
當前Java 8的JVM有700多個Final參數(另外還有大量實驗性的參數)。性能優化是多輪迭代的過程,需要人工反復收集大量的數據一輪一輪地進行。最好每次只優化一個方面。通過以下推薦的GC日志數據,可以得到許多的信息:
Java堆大小的通用計算法則:
Java 7和8中的JVM變化較大,功能越來越強。未來的JVM(可能在Java 9中)將在模塊化上有突破性進展,模塊化有幾年曲折歷史了,相關的JEP都有很多個。
【2015.07.29增加】最值得期待的是下一代Hotspot JVM,叫Graal(http://openjdk.java.net/projects/graal/ ),是動態的編譯器,增加了一種高度可擴展的中間表示IR,可以做更多高級和低級優化:
基于此,Oracle還開發了個多語言的解釋器框架Truffle(https://wiki.openjdk.java.net/display/Graal/Truffle+FAQ+and+Guidelines ),許多語言基于此速度將會更快,例如JRuby,Jython,FastR,Clojure等。基于Truffle實現新的語言將會更加容易。
還有個引人注目的是新一代GC,Shenandoah(http://openjdk.java.net/jeps/189 ): An Ultra-Low-Pause-Time Garbage Collector,超低暫停時間的GC。
當然,老牌項目Jigsaw將會在Java 9 中實現(http://openjdk.java.net/projects/jigsaw/),模塊化帶來的好處之一是性能優化。因為模塊的導入導出包是明確的,JVM可以做很多Whole-Program Optimization Techniques(https://www.voxxed.com/blog/2015/07/the-features-project-jigsaw-brings-to-java-9/ )。
另外,還值得期待的有:
Value Objects 值對象,這樣能方便地支持元組、記錄、基本類型集合了。
http://openjdk.java.net/jeps/169
Project Sumatra: Java on GPU 在JVM級別支持GPGPU并行計算!
http://openjdk.java.net/projects/sumatra/
Project Panama: Native Interconnect for Java (JNI 2.0)
http://mail.openjdk.java.net/pipermail/discuss/2014-March/003306.html
JEP 197: Segmented Code Cache,把代碼緩存根據不同的代碼類型分為三個段,提高性能
http://openjdk.java.net/jeps/197
轉載請注明出處:華為云博客 https://portal.hwclouds.com/blogs
Java spark JVM
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。