パッケージ 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 削除予定のため非推奨: このAPI要素は、将来のバージョンで削除される可能性があります。 リソース管理は、置き換えのない削除のために推奨されていません。ResourceContext 削除予定のため非推奨: このAPI要素は、将来のバージョンで削除される可能性があります。 リソース管理は、置き換えのない削除のために推奨されていません。ResourceId 削除予定のため非推奨: このAPI要素は、将来のバージョンで削除される可能性があります。 リソース管理は、置き換えのない削除のために推奨されていません。ResourceMeter 削除予定のため非推奨: このAPI要素は、将来のバージョンで削除される可能性があります。 リソース管理は、置き換えのない削除のために推奨されていません。ResourceRequest 削除予定のため非推奨: このAPI要素は、将来のバージョンで削除される可能性があります。 リソース管理は、置き換えのない削除のために推奨されていません。 -
クラスのサマリー クラス 説明 BoundedMeter 削除予定のため非推奨: このAPI要素は、将来のバージョンで削除される可能性があります。 リソース管理は、置き換えのない削除のために推奨されていません。NotifyingMeter 削除予定のため非推奨: このAPI要素は、将来のバージョンで削除される可能性があります。 リソース管理は、置き換えのない削除のために推奨されていません。ResourceContextFactory 削除予定のため非推奨: このAPI要素は、将来のバージョンで削除される可能性があります。 リソース管理は、置き換えのない削除のために推奨されていません。ResourceType 削除予定のため非推奨: このAPI要素は、将来のバージョンで削除される可能性があります。 リソース管理は、置き換えのない削除のために推奨されていません。SimpleMeter 削除予定のため非推奨: このAPI要素は、将来のバージョンで削除される可能性があります。 リソース管理は、置き換えのない削除のために推奨されていません。ThrottledMeter 削除予定のため非推奨: このAPI要素は、将来のバージョンで削除される可能性があります。 リソース管理は、置き換えのない削除のために推奨されていません。 -
列挙型のサマリー 列挙型 説明 ResourceAccuracy 削除予定のため非推奨: このAPI要素は、将来のバージョンで削除される可能性があります。 リソース管理は、置き換えのない削除のために推奨されていません。 -
例外のサマリー 例外 説明 ResourceRequestDeniedException 削除予定のため非推奨: このAPI要素は、将来のバージョンで削除される可能性があります。 リソース管理は、置き換えのない削除のために推奨されていません。