JDK8垃圾回收調優指南--(6)並行收集器

原文:Java Platform, Standard Edition HotSpot Virtual Machine Garbage Collection Tuning Guide--The Parallel Collector

並行收集器(也稱爲吞吐量收集器),與串行收集器類似都是分代收集器;主要的區別是使用多個線程來加速垃圾回收。
使用命令行選項'-XX:+UseParallelGC'啓用並行收集器。默認情況下,使用此選項,'minor collection'和'major collection'都會並行執行,以進一步減少垃圾收集開銷。

在擁有N(N>8)個硬件線程的機器上,並行收集器使用固定比例的N值作爲垃圾收集器線程的數量。對於N值較大的情況,比例約爲5/8。當N值低於8時,使用的數值爲N。在選定的平臺上,比例下降爲5/16。可以使用命令行選項(稍後將對此進行描述)調整垃圾收集線程的特定數量。在只有一個處理器的主機上,由於並行執行(例如同步,線程間通信)所需的開銷,並行收集器的性能可能不如串行收集器。但是,當運行具有中型到大型堆的應用程序時,在具有兩個處理器的機器上,它的性能通常要比串行收集器好一些,而且當有兩個以上可用處理器時,它的性能通常要比串行收集器更好。

可以使用命令行選項'-XX:ParallelGCThreads=<N>'控制垃圾收集線程的數量。並行收集器和串行收集器一樣,使用命令行對堆值進行調節,以獲取好的性能。但是,啓用並行收集器應該會縮短GC停頓時間。由於多個垃圾收集線程參與'minor collection',因此在GC期間,可能會由於從年輕代提升到老年代,出現一些碎片。'minor collection'涉及的每個垃圾收集線程都保留了部分老年代用於升級,將可用空間劃分到這些“升級緩衝區”可能會導致碎片效應。減少垃圾收集線程的數量,增加老年代的大小可以減少這種碎片效應。

Generations

正如前面提到的,在並行收集器中,代的排列是不同的(相比於串行收集器)。這種排列如圖6-1所示:

Arrangement of Generations in the Parallel Collector

Parallel Collector Ergonomics

在服務器類機器上,默認情況下選擇並行收集器。此外,並行收集器使用一種自動調優方法,允許您指定特定的行爲,而不是代的大小和其他更低層級的調優細節。您可以指定最大GC停頓時間、吞吐量和佔用空間(堆大小)。

  • 最大GC停頓時間:最大GC停頓時間目標由命令行選項'-XX:MaxGCPauseMillis=<N>'指定。這被解釋爲需要<N>毫秒或更少的暫停時間;默認情況下,沒有最大GC停頓時間目標。如果指定了GC停頓時間目標,則(JVM自動)調整堆大小和其他與垃圾收集相關的參數,以使GC停頓時間短於指定的值。這些調整可能會導致垃圾收集器降低應用程序的總體吞吐量,並且不能總是滿足預期的GC停頓時間目標。
  • 吞吐量:吞吐量目標是根據執行垃圾收集花費的時間與垃圾收集之外花費的時間(稱爲應用程序時間)來計算的。目標由命令行選項'-XX:GCTimeRatio=<N>'指定,該選項將垃圾收集時間與應用程序時間的比率設置爲1/(1+<N>)。例如:'-XX:GCTimeRatio=19'設置的目標是總時間的1/20或5%用來GC。默認值爲99,因此垃圾收集的時間目標爲1%。
  • 佔用空間(堆大小):使用選項'-Xmx<N>'指定最大堆佔用空間。此外,收集器有一個隱式的目標,即只要滿足了其他目標,就最小化堆的大小。

Priority of Goals

這些目標的處理順序如下:

  1. 最大GC停頓時間
  2. 吞吐量
  3. 最小內存佔用

首先滿足最大GC停頓時間目標。只有在達到這個目標之後,纔會處理吞吐量目標。同樣,只有在滿足了前兩個目標之後,纔會考慮(內存)空間佔用目標。

Generation Size Adjustments

收集器保存的平均GC停頓時間等統計信息會在每次收集結束時更新。然後進行測試,以確定目標是否已達到,並對代的大小進行任何必要的調整。例外情況是,顯式地GC(例如,對System.gc()的調用)會忽略保存統計信息和調整代的大小。

代的大小的增長和收縮是通過一個固定百分比(相對於代大小的百分比)來完成的,這樣代就可以逐步的增加或減小,直到它的預期大小。增長和收縮的比率不同。默認情況下,代以20%的增量增長,以5%的增量收縮。年輕代增長的百分比由命令行選項'-XX:YoungGenerationSizeIncrement=<Y>'控制,老年代由'-XX:TenuredGenerationSizeIncrement=<T>'控制。代(內存大小)收縮的百分比由命令行選項'-XX:AdaptiveSizeDecrementScaleFactor=<D>'調節。如果增長是百分之X,那麼收縮的百分比是X/D。

如果收集器決定在啓動時增加代(的內存大小),則在增量中添加一個補充百分比。這種補充隨着收集次數的增加而減少,沒有長期效果。該補充的目的是提高啓動時性能。縮減的百分比沒有補充。

如果沒有達到最大GC停頓時間目標,則每次只收縮一個代的大小。如果兩代的暫停時間都超過了目標,則首先收縮暫停時間較大的代的大小。

如果吞吐量目標沒有得到滿足,那麼這兩代的大小都會增加。每一個都按其對總垃圾收集時間的貢獻的比例增加。
例如,如果年輕代的垃圾收集時間佔總收集時間的25%(四分之一),如果年輕代的完全增量爲20%,那麼年輕代將增加5%(20%*25%)。

Default Heap Size

除非在命令行上指定了初始堆大小和最大堆大小,否則將根據計算機上的內存大小計算它們。

Client JVM Default Initial and Maximum Heap Sizes

默認的最大堆大小是物理內存大小(192 MB以下)的一半,否則是物理內存大小(1gb以下)的四分之一。

例如,如果您的計算機有128 MB的物理內存,那麼最大堆大小爲64 MB,如果大於或等於1 GB的物理內存,則最大堆大小爲256 MB。

JVM實際上不會使用最大堆大小,除非您的程序創建了足夠多的對象來需要它。在JVM初始化期間分配的數量要少得多,稱爲初始堆大小。這個數量至少是8mb,否則是物理內存的1/64(1GB以下)。

分配給年輕代的最大空間量是總堆大小的三分之一。

Server JVM Default Initial and Maximum Heap Sizes

默認的初始堆大小和最大堆大小在服務器JVM上的工作方式類似於在客戶機JVM上的工作方式,只是默認值可以更高。在32位jvm上,如果有4 GB或更多的物理內存,默認的最大堆大小可以達到1 GB。在64位jvm上,如果有128 GB或更多的物理內存,默認的最大堆大小可以達到32 GB。您總是可以通過直接指定這些值來設置更高或更低的初始堆和最大堆。

Specifying Initial and Maximum Heap Sizes

可以使用命令行'-Xms'(初始堆值)和'-Xmx'(最大堆值)指定初始堆大小和最大堆大小。如果知道應用程序需要多少堆才能正常工作更好,可以將'-Xms'和'-Xmx'設置爲相同的值。如果沒有,JVM將從使用初始堆大小開始,然後增長Java堆,直到找到堆使用和性能之間的平衡。

其他參數和選項可以影響這些默認值。要驗證默認值,請使用'-XX:+PrintFlagsFinal'選項並在輸出中查找'MaxHeapSize'。例如,在Linux或Solaris上,可以運行以下命令:“java -XX:+PrintFlagsFinal <GC options> -version | grep MaxHeapSize”。

Excessive GC Time and OutOfMemoryError

如果在垃圾收集中花費了太多的時間,並行收集器將拋出OutOfMemoryError:如果超過98%的總時間花費在垃圾收集中,並且回收的堆不足2%,那麼將拋出OutOfMemoryError。該特性旨在防止應用程序長時間運行,同時由於堆太小而很少或沒有進展。如果需要,可以通過在命令行中添加選項'-XX:-UseGCOverheadLimit'禁用此功能。

Measurements

並行收集器的詳細垃圾收集器輸出與串行收集器的輸出本質上是相同的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章