パッケージ jdk.management.resource
このアーキテクチャは3つの主要コンポーネントを識別します。
- リソース追跡API - 各
ResourceContext
に対して、リソース・メーターとバインド・スレッドのコンテキストを提供します。ResourceContextFactory
は、ResourceContextへのアクセスと、APIへの主要なエントリ・ポイントを提供します。ResourceContext
には、ResourceContextにバインドされているスレッド別にリソースの使用量を追跡する、一連のResourceMeterが含まれています。ResourceType
は、リソースのタイプを特定する場合に使用します。 たとえば、FILE_OPEN (ファイルを開く)
やSOCKET_WRITE (ソケットへの書込み)
などがあります。ResourceMeter
は、ResourceTypeの使用状況を追跡します。 ResourceMeter (SimpleMeter
、NotifyingMeter
、BoundedMeter
およびThrottledMeter
)は、リソース使用をカウントして、リソース使用の承認、スロットリングまたは拒否を行います。ResourceId
は、特定のリソースと測定値の精度を識別します。ResourceApprover
は、リソース・マネージャによって実装されるインタフェースであり、リソース使用が通知されます。 リソース・マネージャからのレスポンスによって、リソースの承認、制限または拒否が決まります。
- リソース計装 - 特定のJava Runtimeサブシステムのフックを実装して、情報を収集し、リソース承認をリクエストし、リソース・アクセスを許可、制限、または拒否するメカニズムを適用します。 各リソースの計測では、呼出し元スレッドに関連付けられているResourceContextを動的に探して、
ResourceRequest
を対応するResourceTypeに転送します。 ネイティブ・ライブラリやファイル記述子やソケットなどの仮想マシンで使用されるリソースは、計測も追跡もされません。 計測対象のリソースは次のとおりです。- FileDescriptor - オープン・ファイル記述子の数、合計
- 明示的ファイルに関連付けられたFileDescriptor
- ソケットおよびソケット・チャネルに関連付けられたFileDescriptor
- ファイル - オープン・ファイルの数、送信バイト数、受信バイト数、合計
- FileInputStream、FileOutputStream、RandomAccessFile
- 同期および非同期のNIO FileChannel
- 標準ストリーム(
System.err
、System.in
、System.out
)
- ソケットおよびダイアグラム - オープン・ソケットの数、送信バイト数、受信バイト数、送信ダイアグラム、受信ダイアグラム、合計
- Socket、ServerSocket、DatagramSocket
- NIO SocketChannelおよびDatagramChannel
- NIO AsynchronousSocketChannel
- ヒープ - 割当て済バイト数、保持されたバイト数、合計割当て
- スレッド - アクティブなスレッド数、リソース・コンテキスト当たりのCPU時間
- FileDescriptor - オープン・ファイル記述子の数、合計
- リソース・マネージャ - リソース使用量の監視とリソース・ポリシーの実装を行う信頼できる外部エンティティ。 リソース・マネージャは、アプリケーション・ドメインのリソース・コンシューマ・スレッドを
ResourceContext
とバインドします。 リソース・マネージャおよびリソース管理ポリシーは含まれていません。
リソース管理はセキュリティで保護されたAPIであり、APIへのアクセスはSecurityManager (ある場合)およびRuntimePermission("jdk.management.resource.getResourceContextFactory")
によって許可されます。
コマンド行オプション-XX:+ResourceManagement
、-XX:ResourceManagementSampleInterval=nn (milliseconds)
および-XX:+UseG1GC
を使用してリソース追跡を適宜有効化すると、保持されたヒープ量が確保されます。
リソースのアカウンティングとスレッド化
ライブラリ・ベースのリソースの場合、ファイルのオープン、ストリームの読取りなどでリソースを消費しているスレッドを使って使用状況を測定し、ResourceMeterに記録します。 計測は、アクティビティを記録する共通のパブリックAPIに割り込むことによって実施されます。
アプリケーション・スレッドの使用は保護されています。 リソース・マネージャがアプリケーションと競合しないようにし、また、リソース管理計測への再帰コールを引き起こす可能性がある関数を呼び出さないようにする必要があります。 ResourceRequestインタフェースとResourceApproverインタフェースの実装は、簡潔、軽量および自己完結型であることが必要です。 これらのインタフェースを介した呼出しは非常に頻繁に発生するため、計測対象のすべてのリソースのパフォーマンスに影響を及ぼす可能性があります。 たとえば、デバッグ出力を挿入するためにSystem.out.println
を呼び出すと、再帰コールが発生します。 これにより、予期しないループが発生したり、クラスの初期化が不完全になる可能性があります。 たとえば、StackOverflowErrorやExceptionInInitializerErrorなどの現象があります。
リソース割当ての場合、リソース・マネージャ・ポリシーでリソースの使用を遅くしたり拒否したりできるように、通常、メーターの更新はアクションが実行される前に行われます。 リソースの解放はリソースが解放された後に発生するので、リソース数が処理途中で減分されることはありません。 割当て済で未使用のリソースは、その残りの部分が解放されます。 たとえば、ファイルを開いたときにSecurityExceptionが発生すると、オープン・ファイル数のカウントが減り、ファイルの読取り時にファイルから読み取られたデータ量がリクエストされた量よりも少ない場合は、読み取られなかったバイト数分のカウントが減ります。
ファイル・リソースの追跡
ファイルのオープン、読取りおよび書込みに使用されるリソースについては、AsynchronousFileChannel
、FileChannel
、FileInputStream
、FileOutputStream
およびRandomAccessFile
の各クラスが追跡されます。 報告されたResourceId
は、APIに指定されたパス名です(ただし、AsynchronousFileChannel
の場合は除き、そこではFileDescriptor
番号またはハンドルがResourceIdになります)。 アプリケーションのスレッドを使用して次のメソッドを計測し、指定のResourceMeterにリソース使用量を累計します。 リソースの使用を拒否するには、ResourceApproverまたはResourceMeterでゼロ(0)を返すかResourceRequestDeniedExceptionをスローします。 拒否されると、I/O操作がIOExceptionで失敗します。
ファイルを開くと、それが閉じるまでResourceContextが記憶されます。 チャネルまたはファイルを閉じると、開いたときと同じResourceContext
のカウントが減ります。
ResourceType |
増分 | 減分 | 量 |
---|---|---|---|
FILE_OPEN |
AsynchronousFileChannel.open 、FileChannel.open 、FileInputStream 、FileOutputStream 、RandomAccessFile |
AsynchronousFileChannel.close 、FileChannel.close 、FileInputStream.close 、FileOutputStream.close 、RandomAccessFile.close |
1 |
FILE_READ |
AsynchronousFileChannel.read 、FileChannel.read 、FileInputStream.read 、RandomAccessFile.read メソッド、System.in.read |
リクエストされた読取りバイト数から実際の読取りバイト数を差し引いた数 | length |
FILE_WRITE |
AsynchronousFileChannel.write 、FileChannel.write 、FileOutputStream.write 、RandomAccessFile.write メソッド、System.err 出力および書込みメソッド、System.out 出力および書込みメソッド |
例外 | length |
ファイル記述子の追跡
ファイル記述子がチャネル、ファイルおよびソケットを開く場合に使用するリソースが追跡されます。 ファイル記述子が決まる前にリソース・チェックが行われる可能性があるため、ファイル記述子を割り当てるためのリソース・リクエストには、必ずしもファイル記述子のResourceIdを指定する必要はありません。 ただし、使用可能な場合には、ファイル記述子番号またはハンドラがResourceIdの名前として使用されます。 アプリケーションのスレッドを使用して次のメソッドを計測し、指定のResourceMeterにリソース使用量を累計します。 リソースの使用を拒否するには、ResourceApproverまたはResourceMeterでゼロ(0)を返すかResourceRequestDeniedExceptionをスローします。 拒否されると、I/O操作がIOExceptionで失敗します。
ファイル記述子が割り当てられると、それが閉じるまでResourceContextが記憶されます。 ファイル記述子を閉じると、開いたときと同じResourceContext
のカウントが減ります。
ResourceType |
増分 | 減分 | 量 |
---|---|---|---|
FILEDESCRIPTOR_OPEN |
AsynchronousFileChannel.open 、AsynchronousServerSocketChannel.accept 、AsynchronousServerSocketChannel.open 、AsynchronousSocketChannel.open 、DatagramChannel.open 、DatagramSocket 、FileChannel.open 、FileInputStream 、FileOutputStream 、RandomAccessFile 、ServerSocketChannel.accept 、ServerSocketChannel.open 、ServerSocket (バインドしている場合)、ServerSocket.accept 、ServerSocket.bind (バインドしていない場合)、Socket (接続している場合)、Socket.connect (接続していない場合) SocketChannel.open |
AsynchronousFileChannel.close 、AsynchronousServerSocketChannel.close 、AsynchronousSocketChannel.close 、DatagramChannel.close 、DatagramSocket.close 、FileChannel.close 、FileInputStream.close 、FileOutputStream.close 、RandomAccessFile.close 、ServerSocketChannel.close 、ServerSocket.close 、Socket.close 、SocketChannel.close |
1 |
前述の内容について、リソース数が更新されるタイミングは、ファイル記述子の対応するネイティブな類似機能が割り当てられるか閉じられるときです。
ServerSocket
およびSocket
の場合は、それぞれソケットのバインド時または接続時です。 バインドや接続が行われるのは、ソケットのインスタンス化中またはインスタンス化後です。
ソケット・リソースの追跡
ソケット経由でデータを開いたり送受信する場合に使用されるリソースについては、ソケットとソケット・チャネル、ダイアグラム・ソケットとダイアグラム・チャネル、および非同期ソケット・チャネルが追跡されます。 これにはSSLサーバーとクライアントのソケットを含みます。 報告されるResourceIdは、ローカル・ネットワーク・ポートのアドレスです。 アプリケーションのスレッドを使用して次のメソッドを計測し、指定のResourceMeterにリソース使用量を累計します。 リソースの使用を拒否するには、ResourceApproverまたはResourceMeterでゼロ(0)を返すかResourceRequestDeniedExceptionをスローします。 拒否されると、I/O操作がIOExceptionで失敗します。
ソケットを開くと、それが閉じるまでResourceContextが記憶されます。 チャネル・ソケットを閉じると、開いたときと同じResourceContext
のカウントが減ります。
ResourceType |
増分 | 減分 | 量 |
---|---|---|---|
SOCKET_OPEN |
AsynchronousServerSocketChannel.accept 、AsynchronousServerSocketChannel.bind (バインドされていない場合)、AsynchronousSocketChannel.bind (バインドされていない場合)、AsynchronousSocketChannel.connect (バインドされていない場合)、ServerSocketChannel.bind (バインドされていない場合)、ServerSocket.accept 、ServerSocket.bind (バインドされていない場合)、Socket.bind (バインドされていない場合)、Socket.connect (バインドされていない場合)、SocketChannel.bind (バインドされていない場合)、SocketChannel.connect (バインドされていない場合) |
AsynchronousServerSocketChannel.close 、AsynchronousSocketChannel.close 、ServerSocketChannel.close 、ServerSocket.close 、Socket.close 、SocketChannel.close |
1 |
SOCKET_READ |
AsynchronousSocketChannel.read 、Socket.getInputStream().read 、SocketChannel.read |
リクエストされた読取りバイト数から実際の読取りバイト数を差し引いた数 | length |
SOCKET_WRITE |
AsynchronousSocketChannel.write 、Socket.getOutputStream().write 、SocketChannel.write |
例外 | length |
前述の内容について、
SOCKET_OPEN
リソース数が増分されるタイミングは、オブジェクトの作成時ではなく、オブジェクトのバインド時です。 バインドが行われるのは、ソケットがまだバインドされていない場合に接続したときです。
データグラム・リソースの追跡
データグラムを開いたり送受信する場合に使用されるリソースについては、DatagramChannel
およびDatagramSocket
の各クラスが追跡されます。 報告されるResourceIdは、ローカル・ネットワーク・ポートのアドレスです。 アプリケーションのスレッドを使用して次のメソッドを計測し、指定のResourceMeterにリソース使用量を累計します。 リソースの使用を拒否するには、ResourceApproverまたはResourceMeterでゼロ(0)を返すかResourceRequestDeniedExceptionをスローします。 拒否されると、I/O操作がIOExceptionで失敗します。
DatagramSocketを開くと、それが閉じるまでResourceContextが記憶されます。 チャネルまたはソケットを閉じると、開いたときと同じResourceContext
のカウントが減ります。
ResourceType |
増分 | 減分 | 量 |
---|---|---|---|
DATAGRAM_OPEN |
DatagramChannel.bind 、DatagramChannel.connect 、DatagramChannel.send 、DatagramSocket.bind 、DatagramSocket.connect |
DatagramChannel.close 、DatagramSocket.close |
1 |
DATAGRAM_RECEIVED |
DatagramChannel.read 、DatagramChannel.receive 、DatagramSocket.receive |
例外 | 1 |
DATAGRAM_SENT |
DatagramChannel.send 、DatagramChannel.write 、DatagramSocket.send |
例外 | 1 |
DATAGRAM_READ |
DatagramChannel.read 、DatagramChannel.receive 、DatagramSocket.receive |
リクエストされた読取りバイト数から実際の読取りバイト数を差し引いた数 | +ダイアグラムの長さ |
DATAGRAM_WRITE |
DatagramChannel.send 、DatagramChannel.write 、DatagramSocket.send |
例外 | +ダイアグラムの長さ |
前述の内容について、
DATAGRAM_OPEN
リソース数が増分されるタイミングは、オブジェクトの作成時ではなく、オブジェクトのバインド時です。 バインドが行われるのは、ソケットがまだバインドされていない場合に接続したとき(DatagramChannel
の場合は送信したとき)です。
スレッド・リソースの追跡
スレッド・リソースを追跡するには、スレッドを監視して、スレッドにバインドされているResourceContext内のResourceMeterに報告します。 スレッドが作成されて終了すると、THREAD_CREATED
メーターが更新されます。 例外がスローされると、スレッドの作成は実行されません。 メーターから返された量がゼロ(0)の場合、ResourceRequestDeniedExceptionがスローされます。
スレッドがResourceContextからアンバインドされると、スレッドがコンテキストにバインドされてからのCPU時間の累積使用量が、スレッドにバインドされているResourceContext
内のTHREAD_CPU
ResourceMeterに適用されます。 更新はアンバインドされるスレッドを使用して実行されます。
システム・スレッド以外のスレッドは、最初はunassignedContext
に対してバインドされます。 新しいスレッドは、新しいThread
を起動するスレッドのResourceContextに暗黙的にバインドされます。 ThreadのRunnable
は、必要に応じて目的のコンテキストに明示的にバインド
する必要があります。
定期的な更新は監視スレッドで実行します。監視スレッドは、各ResourceContext内でアクティブなスレッドをサンプリングし、各スレッドのCPU時間の更新を実行します。 ResourceApproverまたはResourceMeterのアクションでは、ゼロ(0)を返したり、ResourceRequestDeniedExceptionをスローすることがありますが、それがリソースを使用しているアプリケーションに影響するかどうかは、プラットフォームによって異なります。 更新のタイミングはサンプリングによって異なる場合があります。 THREAD_CPU
メーターの粒度を設定した場合の正常な動作では、粒度境界を越えたときに通知が発生します。 サンプリング間隔は、コマンド・ライン・スイッチ-XX:ResourceManagementSampleInterval=nn
を使用した実装で設定されます。 デフォルトのサンプリング間隔は100ミリ秒(0.1秒)ごとです。 サンプリングを無効化するには、引数0 (ゼロ)
を指定します。 引数がゼロ(0)よりも小さい場合は、デフォルトが使用されます。
THREAD_CREATED
およびTHREAD_CPU
に報告されるResourceIdは、Long.toString(threadID)
という形式のthreadID
です。
スレッドが作成されると、終了するまでResourceContext
が記憶されます。 スレッドが終了すると、開いたときと同じResourceContext
の作成済スレッドのカウントが減ります。
ResourceType |
増分 | 減分 | 量 |
---|---|---|---|
THREAD_CPU |
実行中のスレッド | なし | ナノ秒 |
THREAD_CREATED |
スレッドの構築 | スレッドの終了 | カウント |
ヒープ・リソースの追跡
ヒープ・リソースを追跡するには、スレッドとガベージ・コレクタのアクティビティを監視して、スレッドにバインドされているResourceContext内のResourceMeterに使用状況を報告します。
スレッドがResourceContextからアンバインドされると、スレッドがコンテキストにバインドされてからのヒープ割当ての累積使用量が、スレッドにバインドされているResourceContext内のHEAP_ALLOCATED
ResourceMeter
に適用されます。 更新はアンバインドされるスレッドを使用して実行されます。 HEAP_ALLOCATED
値のサンプリング間隔はTHREAD_CPU
メーターと同じです。 ResourceIdはHEAP_ALLOCATED
のthreadId
であり、スレッドごとに個別に報告されます。
HEAP_RETAINED
の使用量については、ガベージ・コレクタのアクティビティの結果として更新が発生します。 GCフェーズが終了すると、HEAP_RETAINED
の各メーターが更新されます。 保持されたヒープ量の精度は、ResourceId.getAccuracy
メソッドからResourceAccuracy
値として提供されます。 ResourceApproverまたはResourceMeterのアクションでは、ゼロ(0)を返したり、ResourceRequestDeniedExceptionをスローすることがありますが、それがリソースを使用しているアプリケーションに影響するかどうかは、プラットフォームによって異なります。 ResourceAccuracy.HIGHまたはResourceAccuracy.HIGHESTが指定されたHEAP_RETAINEDの更新は常に、メーターに設定された粒度に関係なく実施されます。 更新のタイミングはサンプリングやGC動作によって異なる場合があります。 HEAP_RETAINED
のResourceIdは"Heap"
です。
ResourceType |
増分 | 減分 | 量 |
---|---|---|---|
HEAP_ALLOCATED |
オブジェクト割当て | なし | 割当てバイト数(上限) |
HEAP_RETAINED |
GCフェーズの終了時 | GCフェーズの終了時 | 保持されたバイト数(上限) |
FileOutputStreamによって書き込まれたバイト数をSimpleMeterを使用してカウントする例
void test1() {
ResourceContextFactory rfactory = ResourceContextFactory.getInstance();
ResourceContext rc1 = rfactory.create("context1");
ResourceMeter writeMeter = SimpleMeter.create(ResourceType.FILE_WRITE);
rc1.addResourceMeter(writeMeter);
rc1.bindThreadContext();
try {
long bytesWritten = writeFile("example1.tmp");
assert bytesWritten == writeMeter.get() : "Expected: " + bytesWritten + ", actual: " + writeMeter.get();
} finally {
ResourceContext.unbindThreadContext();
}
}
NotifyingMeterとコールバックを使用してバイト数をカウントする例
public void test1() {
ResourceContextFactory rfactory = ResourceContextFactory.getInstance();
ResourceContext rcontext = rfactory.create("test");
SimpleMeter fileOpenMeter = SimpleMeter.create(ResourceType.FILE_OPEN);
rcontext.addResourceMeter(fileOpenMeter);
SimpleMeter fileWriteMeter = SimpleMeter.create(ResourceType.FILE_WRITE);
rcontext.addResourceMeter(fileWriteMeter);
SimpleMeter threadCPUMeter = SimpleMeter.create(ResourceType.THREAD_CPU);
rcontext.addResourceMeter(threadCPUMeter);
SimpleMeter heapAllocMeter = SimpleMeter.create(ResourceType.HEAP_ALLOCATED);
rcontext.addResourceMeter(heapAllocMeter);
AtomicLong progress = new AtomicLong();
NotifyingMeter fileReadMeter = NotifyingMeter.create(ResourceType.FILE_READ,
(ResourceMeter c, long prev, long amt, ResourceId id) -> {
// total up the lengths of the positive requests
progress.getAndAdd(Math.max(0, amt));
return amt;
});
rcontext.addResourceMeter(fileReadMeter);
rcontext.bindThreadContext();
try {
FileConsumer fc = FileConsumer.create();
fc.write();
fc.read();
} catch (IOException ioe) {
System.out.printf("ioe: %s%n", ioe);
} finally {
ResourceContext.unbindThreadContext();
}
System.out.printf(" cpu: %9d ns%n", threadCPUMeter.getValue());
System.out.printf(" file open: %9d bytes%n", fileOpenMeter.getValue());
System.out.printf(" file read: %9d bytes%n", fileReadMeter.getValue());
System.out.printf(" file write: %9d bytes%n", fileWriteMeter.getValue());
System.out.printf(" heap total: %9d bytes%n", heapAllocMeter.getValue());
System.out.printf(" progress: %9d bytes%n", progress.get());
}
出力の生成
cpu: 76960825 ns
file open: 8 bytes
file read: 82639 bytes
file write: 82639 bytes
heap total: 801624 bytes
progress: 99188 bytes
- 実装要件:
- 特に指定しない限り、
null
を引数としてコンストラクタまたはメソッドに渡すと、NullPointerException
がスローされます。 - 導入されたバージョン:
- 8u40
- 商用機能
- これは、使用する前にロックを解除する必要のある商用機能です。 商用機能の詳細とロック解除方法については、http://www.oracle.com/technetwork/java/javaseproducts/をご覧ください。
-
インタフェースのサマリー インタフェース 説明 ResourceApprover ResourceApproverは、リソース・リクエストを承認するためのコールバックです。ResourceContext リソース使用量をスレッド別に累計するResourceMeterのセットです。ResourceId ResourceIdは、リソース・インスタンスの名前と精度を提供します。ResourceMeter 現在の値とResourceTypeを持つリソース・メーターです。ResourceRequest ResourceRequestは、リソースの割当てや解放を行うためのインタフェースです。 -
クラスのサマリー クラス 説明 BoundedMeter BoundedMeterは、上限を適用し、オプションの親からの変更および割当てに対して承認者のコールバックを提供します。NotifyingMeter NotifyingMeterは、オプションの親からの変更および割当てに対して承認者のコールバックを提供します。ResourceContextFactory ResourceContextFactoryは、ResourceContext機能へのアクセスを提供します。ResourceType ResourceTypeでは名前を指定します。SimpleMeter SimpleMeterは、リソース・リクエスト、およびオプションの親からの解放と割当てをカウントします。ThrottledMeter ThrottledMeterでは、帯域幅制限、オプションの親からのリクエストおよび割当てに対する承認者のコールバックを指定します。 -
列挙型のサマリー 列挙型 説明 ResourceAccuracy ResourceAccuracyは、ResourceMeterを介してリクエストされる量の精度を反映します。 -
例外のサマリー 例外 説明 ResourceRequestDeniedException ResourceRequestDeniedExceptionは、リソース例外を示します。