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
など)と配列クラスが変更可能になることはありません。
theClass
- 変更可能かどうかをチェックするクラス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(tm)仮想マシン仕様』には、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()
メソッドを呼び出すことで取得され、これはappendToClassPathForInstrumentation
メソッドへのパラメータとして提供されます。
『Java(tm)仮想マシン仕様』には、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, 2014, Oracle and/or its affiliates. All rights reserved.