GC微調實踐

垃圾回收微調與其它的性能微調活動沒有什麼區別。
不屈服於對應用程序的隨機部分進行調整,你需要確保你理解當前的情況和期望的結果。

通常按照以下過程來處理容易些。
1.聲明你的性能目標
2.運行測試
3.測量
4.和目標進行比較
5.改變並回歸測試

設定與性能微調相關的目標和可測量的三維是很重要的。這些目標包括延遲,吞吐量和容量,爲了更好的理解我推薦大家看一下 垃圾回收手冊 中對應的章節。

我們看看怎樣在實踐中設置和達成目標。出於這個目的,我們看一下一個示例代碼。

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class Producer implements Runnable {

private static ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2);

private Deque<byte[]> deque;
private int objectSize;
private int queueSize;

public Producer(int objectSize, int ttl) {
  this.deque = new ArrayDeque<byte[]>();
  this.objectSize = objectSize;
  this.queueSize = ttl * 1000;
}

@Override
public void run() {
  for (int i = 0; i < 100; i++) {
    deque.add(new byte[objectSize]);
    if (deque.size() > queueSize) {
      deque.poll();
    }
  }
}

public static void main(String[] args) throws InterruptedException {
  executorService.scheduleAtFixedRate(new Producer(200 * 1024 * 1024 / 1000, 5), 0, 100, TimeUnit.MILLISECONDS);
  executorService.scheduleAtFixedRate(new Producer(50 * 1024 * 1024 / 1000, 120), 0, 100, TimeUnit.MILLISECONDS);
  TimeUnit.MINUTES.sleep(10);
  executorService.shutdownNow();
}
}

這段代碼每100毫秒提交兩個任務。每個任務模擬指定生命週期的對象:創建對象,在預定時間內讓他們離開並且忘掉他們,允許GC回收內存。

當運行示例代碼時打開GC日誌記錄,參數如下:

-XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps

我們開始看到上述參數對垃圾回收日誌的影響,類似下面的輸出:


2015-06-04T13:34:16.119-0200: 1.723: [GC (Allocation Failure) [PSYoungGen: 114016K->73191K(234496K)] 421540K->421269K(745984K), 0.0858176 secs] [Times: user=0.04 sys=0.06, real=0.09 secs] 
2015-06-04T13:34:16.738-0200: 2.342: [GC (Allocation Failure) [PSYoungGen: 234462K->93677K(254976K)] 582540K->593275K(766464K), 0.2357086 secs] [Times: user=0.11 sys=0.14, real=0.24 secs] 
2015-06-04T13:34:16.974-0200: 2.578: [Full GC (Ergonomics) [PSYoungGen: 93677K->70109K(254976K)] [ParOldGen: 499597K->511230K(761856K)] 593275K->581339K(1016832K), [Metaspace: 2936K->2936K(1056768K)], 0.0713174 secs] [Times: user=0.21 sys=0.02, real=0.07 secs]

基於日誌信息我們能在頭腦中開始改進三種不同目標的情況。

1.確保最糟糕的情況GC暫停不超過一個預定值。
2.確保被停止的應用程序線程的總時間不超過一個預定值。
3.當確保我們能完成合理的延遲或者吞吐量目標時,減少基礎消耗。

爲了實現這個,上述代碼用三種不同的配置運行10分鐘導致三種
不同的結果,總結在下表中:

這裏寫圖片描述

用不同的垃圾回收算法和不同的堆大小運行的試驗來測量關於延遲和吞吐量的垃圾回收暫停的持續時間。

試驗的細節和結果的解釋都在我們的 垃圾回收手冊 中。看一下手冊中的例子,簡單的配置改變是怎樣把例子中關於延遲,吞吐量和容量變得完全不同的。

另外,我們了保持例子儘可能的簡單,只是改變了限定數量的輸入參數,例如試驗並沒有在不同數量的核心或者不同的堆佈局下進行測試。

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