1

Javaのガベージコレクタ(GC)が必ずしもメインスレッドを停止するとは限りません。すべてのスレッドをブロックするか、他のスレッドを一時停止することなく並行して実行することができます。ガベージコレクション時間のブロック部分の測定

合計ガベージコレクション時間は、プログラムの最後に garbageCollectorMXBean.getCollectionTime();を使用するか、または-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -verbose:gcでVMを実行して測定できます。

しかし、メインスレッドがブロックされている(つまり一時停止している)GCの部分を測定したいので、メインスレッドが実行されている正確な時間を測定できます。それを測定することは可能ですか?

+0

質問を編集して、GC休止やメインスレッドの実行時間を測定するかどうかを明確にしてください。これらは2つの全く異なる指標であり、一方は他方の指標から派生していません。 – apangin

+0

時間は1)メインスレッドがGCによって停止されなかった、または2)VMセーフポイントになかった、または3)実際にCPUで実行されていた - これらはすべて異なる時期です。 – apangin

答えて

3

あなたの質問は「メインスレッドが実行されている正確な時間」を測定することだけです。これを知るには、ガベージコレクタのブロック時間を測定する必要はありません。

スレッドが実行された時間は、そのCPU時間に対応します。 I/Oを待っている時間も考慮する必要がある場合は、この方法はうまくいかないでしょうが、ガベージコレクタがスレッドを一時停止する時間は無視してください。

私はあなたのために一緒にコンセプトの簡単な証明を置く:

import java.lang.management.ManagementFactory; 
import java.lang.management.ThreadMXBean; 
import java.util.concurrent.TimeUnit; 

public class CpuTime 
{ 
    public static void main(String[] args) { 

     // We obtain the thread mx bean and check if it support CPU time measuring. 
     final ThreadMXBean threadMxBean = ManagementFactory.getThreadMXBean(); 
     if (!threadMxBean.isThreadCpuTimeSupported()) 
      throw new IllegalStateException("CPU time not supported on this platform"); 

     // This is important because the default value is platform-dependent. 
     threadMxBean.setThreadCpuTimeEnabled(true); 

     // Now we start the measurement ... 
     final long threadId = Thread.currentThread().getId(); 
     final long wallTimeStart = System.nanoTime(); 
     final long cpuTimeStart = threadMxBean.getThreadCpuTime(Thread.currentThread().getId()); 

     // ... and do stupid things to give the garbage collector some work. 
     for (int i = 0; i < 1_000_000_000; i++) { 
      Long l = new Long(i); 
     } 

     // Finally we measure the cpu and wall time. 
     final long wallTime = System.nanoTime() - wallTimeStart; 
     final long cpuTime = threadMxBean.getThreadCpuTime(threadId) - cpuTimeStart; 

     System.out.println("CPU time: " + TimeUnit.NANOSECONDS.toMillis(cpuTime)); 
     System.out.println("Wall time: " + TimeUnit.NANOSECONDS.toMillis(wallTime)); 
    } 
} 

は、このアプローチは絶対に正確な結果を得るためにいくつかの調整が必要であることに注意してください。しかし、それはあなたを始めなければなりません。 GCログおよびMBeanのほかに

+0

ありがとう、非常に印象的です。それにもかかわらず、私のプログラムは、多くのCPUとIOを持つデータ管理アルゴリズムです。問題は、IOから多くのデータが読み取られるため、GCが非常にアクティブになっているだけでなく、かなりの計算量があり、正確な時間を測定するのが複雑になります:-( – Ali

+0

https: //github.com/aragozin/jvm-toolsこのスニペットは、リアルタイムでスレッドごとにCPUと割り当て速度の両方を表示する「生産版」バージョンです。 –

2

使用-XX:+PrintGCApplicationStoppedTimeおよび/または-XX:+PrintGCApplicationConcurrentTime

+0

残念ながら '-XX:+ PrintGCApplicationStoppedTime'は正確ではありませんどのような名前が示唆しているのですか?https://stackoverflow.com/questions/29666057/analysis-on-gc-logs/29673564#29673564。これはスレッド単位では機能しません。 –

+0

@BjörnZurmaarはい、私は知っている(少なくとも、私があなたが言及している答えを書いているので:) Javaの開発者は通常、GCの一時停止であるかどうかに関係なく、一時停止時間に興味があります。元の質問 - 私は説明を求めました。 – apangin

+0

これは、あなたが作者であったというこの回答にリンクする理由の1つでした。私はちょうどこの質問の著者にこれを知らせるためにそれを参照しました。 =) –

1

、そこにも関連情報を暴露するJVMのPERFカウンター。

jcmd.exe PID PerfCounter.print | grep "sun.rt.safepointTime"コマンドは、JVMが起動してからStop-the-World状態になった累積経過時間を表示します。

0

jHiccup、https://www.azul.com/jhiccup/(無料でオープンソース)をご覧ください。これは、アプリケーション以外のすべてがアプリケーションのパフォーマンスに与える影響を測定します。このデータを使用して、JVMなどのエフェクト(GCなど)のためにメインスレッドが実行されていない合計時間を計算できます。しかし、これは他のアプリケーションスレッドによってブロックされているために発生したメインスレッドのポーズを測定しません。

関連する問題