public interface Instrumentation
Instrumentation
インタフェースのインスタンスを取得する方法は 2 つあります。
エージェントクラスを指定する方法で JVM を起動した場合。この場合、Instrumentation
インスタンスは、そのエージェントクラスの premain
メソッドに渡されます。
JVM の開始後にエージェントを開始するメカニズムが JVM に用意されている場合。この場合、Instrumentation
インスタンスは、そのエージェントコードの agentmain
メソッドに渡されます。
これらのメカニズムは、パッケージの仕様 で説明します。
エージェントが Instrumentation
インスタンスを取得すると、インスタンス上のメソッドをいつでも呼び出すことができます。
修飾子と型 | メソッドと説明 |
---|---|
void |
addTransformer(ClassFileTransformer transformer)
提供されたトランスフォーマを登録します。
|
void |
addTransformer(ClassFileTransformer transformer, boolean canRetransform)
提供されたトランスフォーマを登録します。
|
void |
appendToBootstrapClassLoaderSearch(JarFile jarfile)
ブートストラップクラスローダーで定義されるインストゥルメンテーションクラスで JAR ファイルを指定します。
|
void |
appendToSystemClassLoaderSearch(JarFile jarfile)
システムクラスローダーで定義されるインストゥルメンテーションクラスで JAR ファイルを指定します。
|
Class[] |
getAllLoadedClasses()
JVM により現在ロードされているすべてのクラスの配列を返します。
|
Class[] |
getInitiatedClasses(ClassLoader loader)
loader が起動ローダーであるすべてのクラスの配列を返します。 |
long |
getObjectSize(Object objectToSize)
指定されたオブジェクトにより消費される記憶領域の容量の実装固有の近似値を返します。
|
boolean |
isModifiableClass(Class<?> theClass)
|
boolean |
isNativeMethodPrefixSupported()
現在の JVM 構成でネイティブメソッドの接頭辞の設定がサポートされるかどうかを返します。
|
boolean |
isRedefineClassesSupported()
現在の JVM 構成がクラスの再定義をサポートしているかどうかを返します。
|
boolean |
isRetransformClassesSupported()
現在の JVM 構成がクラスの再変換をサポートしているかどうかを返します。
|
void |
redefineClasses(ClassDefinition... definitions)
提供されたクラスファイルを使って提供されたクラスのセットを再定義します。
|
boolean |
removeTransformer(ClassFileTransformer transformer)
提供されたトランスフォーマの登録を解除します。
|
void |
retransformClasses(Class<?>... classes)
指定されたクラスセットを再変換します。
|
void |
setNativeMethodPrefix(ClassFileTransformer transformer, String prefix)
このメソッドは、名前に接頭辞を適用して再試行できるようにして、ネイティブメソッド解決のエラー処理を変更します。
|
void addTransformer(ClassFileTransformer transformer, boolean canRetransform)
canRetransform
が true ならばクラスが 再変換 の場合に、クラスのロード時に呼び出されます。変換が呼び出される順序については、ClassFileTransformer.transform
を参照してください。トランスフォーマが実行中に例外をスローすると、JVM は登録されているその他のトランスフォーマを順に呼び出します。同じトランスフォーマを複数回追加することはできますが、そうするべきではありません。これを避けるには、トランスフォーマクラスの新しいインスタンスを作成してください。
このメソッドはインストゥルメンテーションで使用するためのものです (クラスの仕様を参照)。
transformer
- 登録するトランスフォーマcanRetransform
- このトランスフォーマの変換を再変換できるかどうかNullPointerException
- null
トランスフォーマを渡した場合UnsupportedOperationException
- canRetransform
が true であり、JVM の現在の設定が再変換 (isRetransformClassesSupported()
が false) を許可しない場合void addTransformer(ClassFileTransformer transformer)
addTransformer(transformer, false)
と同じ。
transformer
- 登録するトランスフォーマNullPointerException
- null
トランスフォーマを渡した場合addTransformer(ClassFileTransformer,boolean)
boolean removeTransformer(ClassFileTransformer transformer)
transformer
- 登録を解除するトランスフォーマNullPointerException
- null
トランスフォーマを渡した場合boolean isRetransformClassesSupported()
Can-Retransform-Classes
マニフェスト属性が true
に設定されていて (package specification 参照)、かつ JVM がこの機能をサポートしている場合に限られます。単一の JVM の 1 つのインスタンス生成の間に、このメソッドに複数の呼び出しを行うと、常に同じ答えが返されます。retransformClasses(java.lang.Class<?>...)
void retransformClasses(Class<?>... classes) throws UnmodifiableClassException
この機能は、すでにロード済みのクラスのインストゥルメンテーションを容易にします。クラスがはじめてロードされる時や再定義される時に、その初期クラスファイルバイトを ClassFileTransformer
経由で変換することができます。この関数は、以前に変換が行われたかどうかには関係なく、変換処理を再実行します。この再変換は次の手順で行われます。
canRetransform
が false で追加されたトランスフォーマごとに、最後のクラスのロードまたは再定義中に transform
で返されるバイトが変換の出力として再利用される。これは前回の変換をそのまま再適用することと同じである。ただし、transform
が呼び出されない点が異なる
canRetransform
が true で追加されたトランスフォーマごとに、トランスフォーマ内で transform
メソッドが呼び出される
変換の順序については、transform
メソッドで説明しています。再変換不可能トランスフォーマの自動再適用でも、同じ順序が使用されます。
初期クラスファイルバイトは、ClassLoader.defineClass
または redefineClasses
に渡されたバイト (変換の適用前) を表します。ただし、両者が厳密には一致しないことがあります。定数プールは同じレイアウトまたは内容であるとは限りません。定数プールのエントリ数が異なる可能性があります。定数プールのエントリの順序が異なることがあります。ただし、メソッドのバイトコードで定数プールのインデックスは対応します。一部の属性が存在しない可能性があります。順序が重要でない場合 (メソッドの順序など)、順序が維持されない場合があります。
このメソッドは、同時に 1 つ以上のクラスに対して相互依存の関係にある変更 (クラス A の再変換はクラス B の再変換を必要とするなど) を可能にするためにセット上で動作します。
再変換されたメソッドがアクティブなスタックフレームを持つ場合、アクティブなスタックフレームは元のメソッドのバイトコードを引き続き実行します。再変換されたメソッドは新しい呼び出しで使用されます。
このメソッドは、慣行の JVM セマンティクスの下で発生する初期化を除き、初期化を発生させません。つまり、クラスの再定義では、クラスの初期化子は実行されません。static 変数の値は呼び出し前の値のままに維持されます。
再変換されたクラスのインスタンスは影響を受けません。
再変換によって、メソッドの本体、定数プール、属性が変更されることがあります。ただし、再変換では、フィールドまたはメソッドの追加、削除、あるいは名前の変更、メソッドのシグニチャーの変更、あるいは継承の変更はできません。これらの制約は、将来バージョンで解消される可能性があります。クラスバイトファイルがチェック、検証、およびインストールされるのは、変換の適用後になります。得られるバイトがエラーになると、このメソッドは例外をスローします。
このメソッドが例外をスローした場合、クラスの再変換は行われません。
このメソッドはインストゥルメンテーションで使用するためのものです (クラスの仕様を参照)。
classes
- 再変換するクラスの配列。長さゼロの配列は使用できるが、使用した場合、このメソッドは何も実行しないUnmodifiableClassException
- 指定されたクラスを変更できない場合 (isModifiableClass(java.lang.Class<?>)
から false
が返される)UnsupportedOperationException
- JVM の現在の設定が再変換 (isRetransformClassesSupported()
が false) を許可しないか、再変換でサポートされない変更を加えようとした場合ClassFormatError
- データが有効なクラスを含まなかった場合NoClassDefFoundError
- クラスファイルの名前がクラスの名前と等しくない場合UnsupportedClassVersionError
- クラスファイルバージョン番号がサポートされていない場合ClassCircularityError
- 新しいクラスが循環を含む場合LinkageError
- リンケージエラーが発生した場合NullPointerException
- 提供されたクラス配列またはそのコンポーネントのいずれかが null
の場合。isRetransformClassesSupported()
、addTransformer(java.lang.instrument.ClassFileTransformer, boolean)
、ClassFileTransformer
boolean isRedefineClassesSupported()
Can-Redefine-Classes
マニフェスト属性が true
に設定されていて (package specification 参照)、かつ JVM がこの機能をサポートしている場合に限られます。単一の JVM の 1 つのインスタンス生成の間に、このメソッドに複数の呼び出しを行うと、常に同じ答えが返されます。redefineClasses(java.lang.instrument.ClassDefinition...)
void redefineClasses(ClassDefinition... definitions) throws ClassNotFoundException, UnmodifiableClassException
このメソッドを使用して、既存のクラスファイルバイトへの参照のないクラスの定義を置き換えます。逐次デバッグを行うためにソースから再コンパイルするときに置き換えが行われます。既存のクラスファイルバイトが変換される場合は (バイトコードのインストゥルメンテーション内など)、retransformClasses
を使用してください。
このメソッドは、同時に 1 つ以上のクラスに対して相互依存の関係にある変更 (クラス A の再定義はクラス B の再定義を必要とするなど) を可能にするためにセット上で動作します。
再定義されたメソッドがアクティブなスタックフレームを持つ場合、アクティブなスタックフレームは元のメソッドのバイトコードを引き続き実行します。再定義されたメソッドは新しい呼び出しで使用されます。
このメソッドは、慣行の JVM セマンティクスの下で発生する初期化を除き、初期化を発生させません。つまり、クラスの再定義では、クラスの初期化子は実行されません。static 変数の値は呼び出し前の値のままに維持されます。
再定義されたクラスのインスタンスは影響を受けません。
再定義によって、メソッドの本体、定数プール、属性が変更されることがあります。ただし、再定義では、フィールドまたはメソッドの追加、削除、あるいは名前の変更、メソッドのシグニチャーの変更、あるいは継承の変更はできません。これらの制約は、将来バージョンで解消される可能性があります。クラスバイトファイルがチェック、検証、およびインストールされるのは、変換の適用後になります。得られるバイトがエラーになると、このメソッドは例外をスローします。
このメソッドが例外をスローした場合、クラスの再定義は行われません。
このメソッドはインストゥルメンテーションで使用するためのものです (クラスの仕様を参照)。
definitions
- 対応する定義を使って再定義するクラスの配列。長さゼロの配列は使用できるが、使用した場合、このメソッドは何も実行しないUnmodifiableClassException
- 指定されたクラスを変更できない場合 (isModifiableClass(java.lang.Class<?>)
から false
が返される)UnsupportedOperationException
- JVM の現在の設定が再定義 (isRedefineClassesSupported()
が false) を許可しないか、再定義でサポートされない変更を加えようとした場合ClassFormatError
- データが有効なクラスを含まなかった場合NoClassDefFoundError
- クラスファイルの名前がクラスの名前と等しくない場合UnsupportedClassVersionError
- クラスファイルバージョン番号がサポートされていない場合ClassCircularityError
- 新しいクラスが循環を含む場合LinkageError
- リンケージエラーが発生した場合NullPointerException
- 提供された定義配列またはそのコンポーネントのいずれかが null
の場合ClassNotFoundException
- スローすることはできない (互換性を維持するためにのみ存在する)isRedefineClassesSupported()
、addTransformer(java.lang.instrument.ClassFileTransformer, boolean)
、ClassFileTransformer
boolean isModifiableClass(Class<?> theClass)
true
を返します。クラスが変更不可能な場合、このメソッドは false
を返します。
再変換されるクラスでは、isRetransformClassesSupported()
も true である必要があります。ただし、isRetransformClassesSupported()
の値は、この関数が返す値には影響しません。再定義されるクラスでは、isRedefineClassesSupported()
も true である必要があります。ただし、isRedefineClassesSupported()
の値は、この関数が返す値には影響しません。
プリミティブクラス (java.lang.Integer.TYPE
など) と配列クラスが変更可能になることはありません。
NullPointerException
- 指定されたクラスが null
の場合。retransformClasses(java.lang.Class<?>...)
, isRetransformClassesSupported()
, redefineClasses(java.lang.instrument.ClassDefinition...)
, isRedefineClassesSupported()
Class[] getAllLoadedClasses()
Class[] getInitiatedClasses(ClassLoader loader)
loader
が起動ローダーであるすべてのクラスの配列を返します。提供されたローダーが null
の場合、ブートストラップクラスローダーにより起動されたクラスが返されます。loader
- 起動したクラスリストが返されるローダーlong getObjectSize(Object objectToSize)
objectToSize
- サイズを評価するオブジェクトNullPointerException
- 提供されたオブジェクトが null
の場合。void appendToBootstrapClassLoaderSearch(JarFile jarfile)
「ブートストラップクラスローダー」と呼ばれる仮想マシンの組み込みクラスローダーがクラスの検索に失敗すると、JAR file
内のエントリも検索されます。
このメソッドを複数回使用して、このメソッドが呼び出される順序で検索される複数の JAR ファイルを追加できます。
インストゥルメンテーションをするために、エージェントでは JAR ファイルにブートストラップクラスローダーで定義される以外のクラスまたはリソースが含まれないことを確認してください。この警告の監視に失敗すると、診断するのが困難な予期しない動作になることがあります。たとえばローダー L があり、委譲のための L の親がブートストラップクラスローダーであるとします。また、クラス C が L で定義され、クラス C のメソッドが public でないアクセス用クラス C$1 を参照するとします。JAR ファイルにクラス C$1 が含まれる場合、ブートストラップクラスローダーへの委譲により、C$1 がブートストラップクラスローダーによって定義されます。この例では IllegalAccessError
がスローされてアプリケーションが失敗します。このような問題を避ける 1 つの方法として、インストゥルメンテーションクラスに一意のパッケージ名を使用します。
『Java™ 仮想マシン仕様』には、Java 仮想マシンが以前にシンボリック参照を解決しようとして失敗した場合、その後このシンボリック参照を解決しようとしても、最初に解決しようとした結果としてスローされたエラーと同じエラーで必ず失敗すると記述されています。したがって、Java 仮想マシンが参照を解決できなかったクラスに対応するエントリが JAR ファイルに含まれる場合、その参照を解決しようとしても最初のエラーと同じエラーで失敗します。
jarfile
- ブートストラップクラスローダーがクラスの検索に失敗したときに検索される JAR ファイル。NullPointerException
- jarfile
が null
の場合。appendToSystemClassLoaderSearch(java.util.jar.JarFile)
, ClassLoader
, JarFile
void appendToSystemClassLoaderSearch(JarFile jarfile)
getSystemClassLoader()
を参照) がクラスの検索に失敗したときに、JarFile
内のエントリも検索されます。
このメソッドを複数回使用して、このメソッドが呼び出される順序で検索される複数の JAR ファイルを追加できます。
インストゥルメンテーションするために、エージェントは JAR ファイルにシステムクラスローダーで定義される以外のクラスまたはリソースが含まれないことを確認する必要があります。この警告の監視に失敗すると、診断するのが困難な予期しない動作になることがあります (appendToBootstrapClassLoaderSearch
を参照)。
システムクラスローダーに appendToClassPathForInstrumentation
メソッドが実装されている場合は、検索される JAR ファイルの追加がサポートされます。このメソッドは java.lang.String
型のパラメータ 1 つを取ります。このメソッドは、public
アクセスを備えていなくてもかまいません。JAR ファイルの名前は、jarfile
の getName()
メソッドを呼び出すことで取得され、jarfile は appendToClassPathForInstrumentation
メソッドのパラメータとして提供されます。
『Java™ 仮想マシン仕様』には、Java 仮想マシンが以前にシンボリック参照を解決しようとして失敗した場合、その後このシンボリック参照を解決しようとしても、最初に解決しようとした結果としてスローされたエラーと同じエラーで必ず失敗すると記述されています。したがって、Java 仮想マシンが参照を解決できなかったクラスに対応するエントリが JAR ファイルに含まれる場合、その参照を解決しようとしても最初のエラーと同じエラーで失敗します。
このメソッドは java.class.path
system property
の値を変更しません。
jarfile
- システムクラスローダーがクラスの検索に失敗したときに検索される JAR ファイル。UnsupportedOperationException
- システムクラスローダーが検索される JAR ファイルの追加をサポートしていない場合。NullPointerException
- jarfile
が null
の場合。appendToBootstrapClassLoaderSearch(java.util.jar.JarFile)
, ClassLoader.getSystemClassLoader()
, JarFile
boolean isNativeMethodPrefixSupported()
Can-Set-Native-Method-Prefix
マニフェスト属性が true
に設定されていて (package specification 参照)、かつ JVM がこの機能をサポートしている場合に限られます。単一の JVM の 1 つのインスタンス生成の間に、このメソッドに複数の呼び出しを行うと、常に同じ答えが返されます。setNativeMethodPrefix(java.lang.instrument.ClassFileTransformer, java.lang.String)
void setNativeMethodPrefix(ClassFileTransformer transformer, String prefix)
ClassFileTransformer
に使用すると、ネイティブメソッドをインストゥルメンテーションできます。
ネイティブメソッドはバイトコードを持たないので、直接計測することはできません。したがって、計測可能なネイティブでないメソッドでネイティブメソッドをラップする必要があります。たとえば、次のようなメソッドがあるとします。
native boolean foo(int x);クラスの初期定義時に ClassFileTransformer を使用してクラスファイルを変換すると次のようになります。
boolean foo(int x) { ... record entry to foo ... return wrapped_foo(x); } native boolean wrapped_foo(int x);ここで、
foo
は実際のネイティブメソッドのラッパーで、接頭辞「wrapped_」が付加されています。ただし、「wrapped_」は既存のメソッドの名前の一部として使用されている可能性があるため、接頭辞としては良い選択肢ではありません。「$$$MyAgentWrapped$$$_」のような接頭辞のほうが適切ですが、そうするとこの例が読みにくくなってしまいます。
このラッパーを使えば、ネイティブメソッドの呼び出し時にデータを収集することができます。ところがその場合、このラップ済みメソッドをネイティブ実装にリンクする際に問題が生じます。つまり、メソッド wrapped_foo
は、次のようなネイティブ実装 foo
に解決する必要があります。
Java_somePackage_someClass_foo(JNIEnv* env, jint x)この関数を使うと、接頭辞を指定し、適切な解決が行われるようにすることができます。具体的には、標準の解決が失敗すると、接頭辞を考慮して解決が再試行されます。解決には 2 つの方法があります。JNI 関数
RegisterNatives
を使用した明示的な解決と、通常の自動解決です。 RegisterNatives
を使用する場合、JVM では次の関連付けを行おうとします。
method(foo) -> nativeImplementation(foo)これに失敗すると、指定された接頭辞をメソッド名の先頭に追加して解決が再試行され、次のような正しい解決が得られます。
method(wrapped_foo) -> nativeImplementation(foo)自動解決では、JVM は次の関連付けを行おうとします。
method(wrapped_foo) -> nativeImplementation(wrapped_foo)これに失敗すると、指定された接頭辞を実装名から削除して解決が再試行され、次の正しい解決が得られます。
method(wrapped_foo) -> nativeImplementation(foo)接頭辞が使用されるのは標準の解決が失敗した場合だけなので、ネイティブメソッドのラップは選択的に行えます。 各
ClassFileTransformer
では、独自のバイトコード変換を行うことができるため、複数レイヤーのラッパーを適用できます。そのため、各トランスフォーマには専用の接頭辞が必要です。 変換は順番に適用されるため、接頭辞を適用する場合、接頭辞は変換と同じ順番で適用されます (addTransformer
を参照)。つまり 3 つのトランスフォーマによってラッパーが適用されると、foo
は $trans3_$trans2_$trans1_foo
のようになります。 ただし、2 番目のトランスフォーマで foo
にラッパーが適用されなかった場合は、$trans3_$trans1_foo
のようになります。接頭辞のシーケンスを効率的に決定できるようにするため、途中の接頭辞は、そのネイティブでないラッパーが存在する場合にのみ適用されます。つまりこの例では、$trans1_foo
がネイティブメソッドでなくても、$trans1_foo
が存在するため $trans1_
接頭辞が適用されます。transformer
- この接頭辞を使用してラップする ClassFileTransformer。prefix
- 失敗したネイティブメソッド解決を再試行するときに、ラップされたネイティブメソッドに適用される接頭辞。接頭辞が null
または空の文字列である場合、このトランスフォーマの失敗したネイティブメソッド解決は再試行されません。NullPointerException
- null
トランスフォーマを渡した場合。UnsupportedOperationException
- JVM の現在の設定がネイティブメソッドの接頭辞 (isNativeMethodPrefixSupported()
が false) の設定を許可しない場合。IllegalArgumentException
- トランスフォーマが登録されていない場合 (addTransformer
を参照)。 バグまたは機能を送信
詳細な API リファレンスおよび開発者ドキュメントについては、Java SE のドキュメントを参照してください。そのドキュメントには、概念的な概要、用語の定義、回避方法、有効なコード例などの、開発者を対象にしたより詳細な説明が含まれています。
Copyright © 1993, 2013, Oracle and/or its affiliates. All rights reserved.