public interface Instrumentation
There are two ways to obtain an instance of the Instrumentation
interface:
When a JVM is launched in a way that indicates an agent class. In that case an Instrumentation
instance is passed to the premain
method of the agent class.
When a JVM provides a mechanism to start agents sometime after the JVM is launched. In that case an Instrumentation
instance is passed to the agentmain
method of the agent code.
These mechanisms are described in the package specification.
Once an agent acquires an Instrumentation
instance, the agent may call methods on the instance at any time.
Modifier and Type | Method | Description |
---|---|---|
void |
addTransformer |
Registers the supplied transformer. |
void |
addTransformer |
Registers the supplied transformer. |
void |
appendToBootstrapClassLoaderSearch |
Specifies a JAR file with instrumentation classes to be defined by the bootstrap class loader. |
void |
appendToSystemClassLoaderSearch |
Specifies a JAR file with instrumentation classes to be defined by the system class loader. |
Class[] |
getAllLoadedClasses() |
Returns an array of all classes currently loaded by the JVM. |
Class[] |
getInitiatedClasses |
Returns an array of all classes which loader can find by name via ClassLoader::loadClass , Class::forName and bytecode linkage. |
long |
getObjectSize |
Returns an implementation-specific approximation of the amount of storage consumed by the specified object. |
boolean |
isModifiableClass |
Tests whether a class is modifiable by retransformation or redefinition. |
boolean |
isModifiableModule |
Tests whether a module can be modified with redefineModule . |
boolean |
isNativeMethodPrefixSupported() |
Returns whether the current JVM configuration supports setting a native method prefix. |
boolean |
isRedefineClassesSupported() |
Returns whether or not the current JVM configuration supports redefinition of classes. |
boolean |
isRetransformClassesSupported() |
Returns whether or not the current JVM configuration supports retransformation of classes. |
void |
redefineClasses |
Redefine the supplied set of classes using the supplied class files. |
void |
redefineModule |
Redefine a module to expand the set of modules that it reads, the set of packages that it exports or opens, or the services that it uses or provides. |
boolean |
removeTransformer |
Unregisters the supplied transformer. |
void |
retransformClasses |
Retransform the supplied set of classes. |
void |
setNativeMethodPrefix |
This method modifies the failure handling of native method resolution by allowing retry with a prefix applied to the name. |
void addTransformer(ClassFileTransformer transformer, boolean canRetransform)
canRetransform
is true, when they are retransformed. ClassFileTransformer
defines the order of transform calls. If a transformer throws an exception during execution, the JVM will still call the other registered transformers in order. The same transformer may be added more than once, but it is strongly discouraged -- avoid this by creating a new instance of transformer class. This method is intended for use in instrumentation, as described in the class specification.
transformer
- the transformer to registercanRetransform
- can this transformer's transformations be retransformedNullPointerException
- if passed a null
transformerUnsupportedOperationException
- if canRetransform
is true and the current configuration of the JVM does not allow retransformation (isRetransformClassesSupported()
is false)void addTransformer(ClassFileTransformer transformer)
Same as addTransformer(transformer, false)
.
transformer
- the transformer to registerNullPointerException
- if passed a null
transformerboolean removeTransformer(ClassFileTransformer transformer)
transformer
- the transformer to unregisterNullPointerException
- if passed a null
transformerboolean isRetransformClassesSupported()
Can-Retransform-Classes
manifest attribute is set to true
in the agent JAR file (as described in the package specification) and the JVM supports this capability. During a single instantiation of a single JVM, multiple calls to this method will always return the same answer.void retransformClasses(Class<?>... classes) throws UnmodifiableClassException
This function facilitates the instrumentation of already loaded classes. When classes are initially loaded or when they are redefined, the initial class file bytes can be transformed with the ClassFileTransformer
. This function reruns the transformation process (whether or not a transformation has previously occurred). This retransformation follows these steps:
canRetransform
false, the bytes returned by transform
during the last class load or redefine are reused as the output of the transformation; note that this is equivalent to reapplying the previous transformation, unaltered; except that transform
method is not called. canRetransform
true, the transform
method is called in these transformers The order of transformation is described in ClassFileTransformer
. This same order is used in the automatic reapplication of retransformation incapable transforms.
The initial class file bytes represent the bytes passed to ClassLoader.defineClass
or redefineClasses
(before any transformations were applied), however they might not exactly match them. The constant pool might not have the same layout or contents. The constant pool may have more or fewer entries. Constant pool entries may be in a different order; however, constant pool indices in the bytecodes of methods will correspond. Some attributes may not be present. Where order is not meaningful, for example the order of methods, order might not be preserved.
This method operates on a set in order to allow interdependent changes to more than one class at the same time (a retransformation of class A can require a retransformation of class B).
If a retransformed method has active stack frames, those active frames continue to run the bytecodes of the original method. The retransformed method will be used on new invokes.
This method does not cause any initialization except that which would occur under the customary JVM semantics. In other words, redefining a class does not cause its initializers to be run. The values of static variables will remain as they were prior to the call.
Instances of the retransformed class are not affected.
The supported class file changes are described in JVM TI RetransformClasses. The class file bytes are not checked, verified and installed until after the transformations have been applied, if the resultant bytes are in error this method will throw an exception.
If this method throws an exception, no classes have been retransformed.
This method is intended for use in instrumentation, as described in the class specification.
classes
- array of classes to retransform; a zero-length array is allowed, in this case, this method does nothingUnmodifiableClassException
- if a specified class cannot be modified (isModifiableClass(java.lang.Class<?>)
would return false
)UnsupportedOperationException
- if the current configuration of the JVM does not allow retransformation (isRetransformClassesSupported()
is false) or the retransformation attempted to make unsupported changesClassFormatError
- if the data did not contain a valid classNoClassDefFoundError
- if the name in the class file is not equal to the name of the classUnsupportedClassVersionError
- if the class file version numbers are not supportedClassCircularityError
- if the new classes contain a circularityLinkageError
- if a linkage error occursNullPointerException
- if the supplied classes array or any of its components is null
.boolean isRedefineClassesSupported()
Can-Redefine-Classes
manifest attribute is set to true
in the agent JAR file (as described in the package specification) and the JVM supports this capability. During a single instantiation of a single JVM, multiple calls to this method will always return the same answer.void redefineClasses(ClassDefinition... definitions) throws ClassNotFoundException, UnmodifiableClassException
This method is used to replace the definition of a class without reference to the existing class file bytes, as one might do when recompiling from source for fix-and-continue debugging. Where the existing class file bytes are to be transformed (for example in bytecode instrumentation) retransformClasses
should be used.
This method operates on a set in order to allow interdependent changes to more than one class at the same time (a redefinition of class A can require a redefinition of class B).
If a redefined method has active stack frames, those active frames continue to run the bytecodes of the original method. The redefined method will be used on new invokes.
This method does not cause any initialization except that which would occur under the customary JVM semantics. In other words, redefining a class does not cause its initializers to be run. The values of static variables will remain as they were prior to the call.
Instances of the redefined class are not affected.
The supported class file changes are described in JVM TI RedefineClasses. The class file bytes are not checked, verified and installed until after the transformations have been applied, if the resultant bytes are in error this method will throw an exception.
If this method throws an exception, no classes have been redefined.
This method is intended for use in instrumentation, as described in the class specification.
definitions
- array of classes to redefine with corresponding definitions; a zero-length array is allowed, in this case, this method does nothingUnmodifiableClassException
- if a specified class cannot be modified (isModifiableClass(java.lang.Class<?>)
would return false
)UnsupportedOperationException
- if the current configuration of the JVM does not allow redefinition (isRedefineClassesSupported()
is false) or the redefinition attempted to make unsupported changesClassFormatError
- if the data did not contain a valid classNoClassDefFoundError
- if the name in the class file is not equal to the name of the classUnsupportedClassVersionError
- if the class file version numbers are not supportedClassCircularityError
- if the new classes contain a circularityLinkageError
- if a linkage error occursNullPointerException
- if the supplied definitions array or any of its components is null
ClassNotFoundException
- Can never be thrown (present for compatibility reasons only)boolean isModifiableClass(Class<?> theClass)
true
. If a class is not modifiable then this method returns false
. For a class to be retransformed, isRetransformClassesSupported()
must also be true. But the value of isRetransformClassesSupported()
does not influence the value returned by this function. For a class to be redefined, isRedefineClassesSupported()
must also be true. But the value of isRedefineClassesSupported()
does not influence the value returned by this function.
Primitive classes (for example, java.lang.Integer.TYPE
) and array classes are never modifiable.
theClass
- the class to check for being modifiableNullPointerException
- if the specified class is null
.Class[] getAllLoadedClasses()
Class[] getInitiatedClasses(ClassLoader loader)
loader
can find by name via ClassLoader::loadClass
, Class::forName
and bytecode linkage. That is, all classes for which loader
has been recorded as an initiating loader. If the supplied loader
is null
, classes that the bootstrap class loader can find by name are returned. The returned array does not include hidden classes or interfaces or array classes whose element type is a hidden class or interface. as they cannot be discovered by any class loader.
loader
- the loader whose initiated class list will be returnedloader
can find by name; zero-length if there are nonelong getObjectSize(Object objectToSize)
objectToSize
- the object to sizeNullPointerException
- if the supplied Object is null
.void appendToBootstrapClassLoaderSearch(JarFile jarfile)
When the virtual machine's built-in class loader, known as the "bootstrap class loader", unsuccessfully searches for a class, the entries in the JAR file
will be searched as well.
This method may be used multiple times to add multiple JAR files to be searched in the order that this method was invoked.
The agent should take care to ensure that the JAR does not contain any classes or resources other than those to be defined by the bootstrap class loader for the purpose of instrumentation. Failure to observe this warning could result in unexpected behavior that is difficult to diagnose. For example, suppose there is a loader L, and L's parent for delegation is the bootstrap class loader. Furthermore, a method in class C, a class defined by L, makes reference to a non-public accessor class C$1. If the JAR file contains a class C$1 then the delegation to the bootstrap class loader will cause C$1 to be defined by the bootstrap class loader. In this example an IllegalAccessError
will be thrown that may cause the application to fail. One approach to avoiding these types of issues, is to use a unique package name for the instrumentation classes.
The Java Virtual Machine Specification specifies that a subsequent attempt to resolve a symbolic reference that the Java virtual machine has previously unsuccessfully attempted to resolve always fails with the same error that was thrown as a result of the initial resolution attempt. Consequently, if the JAR file contains an entry that corresponds to a class for which the Java virtual machine has unsuccessfully attempted to resolve a reference, then subsequent attempts to resolve that reference will fail with the same error as the initial attempt.
jarfile
- The JAR file to be searched when the bootstrap class loader unsuccessfully searches for a class.NullPointerException
- If jarfile
is null
.void appendToSystemClassLoaderSearch(JarFile jarfile)
getSystemClassLoader()
) unsuccessfully searches for a class, the entries in the JarFile
will be searched as well. This method may be used multiple times to add multiple JAR files to be searched in the order that this method was invoked.
The agent should take care to ensure that the JAR does not contain any classes or resources other than those to be defined by the system class loader for the purpose of instrumentation. Failure to observe this warning could result in unexpected behavior that is difficult to diagnose (see appendToBootstrapClassLoaderSearch
).
The system class loader supports adding a JAR file to be searched if it implements a method named appendToClassPathForInstrumentation
which takes a single parameter of type java.lang.String
. The method is not required to have public
access. The name of the JAR file is obtained by invoking the getName()
method on the jarfile
and this is provided as the parameter to the appendToClassPathForInstrumentation
method.
The Java Virtual Machine Specification specifies that a subsequent attempt to resolve a symbolic reference that the Java virtual machine has previously unsuccessfully attempted to resolve always fails with the same error that was thrown as a result of the initial resolution attempt. Consequently, if the JAR file contains an entry that corresponds to a class for which the Java virtual machine has unsuccessfully attempted to resolve a reference, then subsequent attempts to resolve that reference will fail with the same error as the initial attempt.
This method does not change the value of java.class.path
system property
.
jarfile
- The JAR file to be searched when the system class loader unsuccessfully searches for a class.UnsupportedOperationException
- If the system class loader does not support appending a a JAR file to be searched.NullPointerException
- If jarfile
is null
.boolean isNativeMethodPrefixSupported()
Can-Set-Native-Method-Prefix
manifest attribute is set to true
in the agent JAR file (as described in the package specification) and the JVM supports this capability. During a single instantiation of a single JVM, multiple calls to this method will always return the same answer.void setNativeMethodPrefix(ClassFileTransformer transformer, String prefix)
ClassFileTransformer
, it enables native methods to be instrumented. Since native methods cannot be directly instrumented (they have no bytecodes), they must be wrapped with a non-native method which can be instrumented. For example, if we had:
native boolean foo(int x);
We could transform the class file (with the ClassFileTransformer during the initial definition of the class) so that this becomes:
boolean foo(int x) { ... record entry to foo ... return wrapped_foo(x); } native boolean wrapped_foo(int x);
Where foo
becomes a wrapper for the actual native method with the appended prefix "wrapped_". Note that "wrapped_" would be a poor choice of prefix since it might conceivably form the name of an existing method thus something like "$$$MyAgentWrapped$$$_" would be better but would make these examples less readable.
The wrapper will allow data to be collected on the native method call, but now the problem becomes linking up the wrapped method with the native implementation. That is, the method wrapped_foo
needs to be resolved to the native implementation of foo
, which might be:
Java_somePackage_someClass_foo(JNIEnv* env, jint x)
This function allows the prefix to be specified and the proper resolution to occur. Specifically, when the standard resolution fails, the resolution is retried taking the prefix into consideration. There are two ways that resolution occurs, explicit resolution with the JNI function RegisterNatives
and the normal automatic resolution. For RegisterNatives
, the JVM will attempt this association:
method(foo) -> nativeImplementation(foo)
When this fails, the resolution will be retried with the specified prefix prepended to the method name, yielding the correct resolution:
method(wrapped_foo) -> nativeImplementation(foo)
For automatic resolution, the JVM will attempt:
method(wrapped_foo) -> nativeImplementation(wrapped_foo)
When this fails, the resolution will be retried with the specified prefix deleted from the implementation name, yielding the correct resolution:
method(wrapped_foo) -> nativeImplementation(foo)
Note that since the prefix is only used when standard resolution fails, native methods can be wrapped selectively.
Since each ClassFileTransformer
can do its own transformation of the bytecodes, more than one layer of wrappers may be applied. Thus each transformer needs its own prefix. Since transformations are applied in order, the prefixes, if applied, will be applied in the same order (see addTransformer
). Thus if three transformers applied wrappers, foo
might become $trans3_$trans2_$trans1_foo
. But if, say, the second transformer did not apply a wrapper to foo
it would be just $trans3_$trans1_foo
. To be able to efficiently determine the sequence of prefixes, an intermediate prefix is only applied if its non-native wrapper exists. Thus, in the last example, even though $trans1_foo
is not a native method, the $trans1_
prefix is applied since $trans1_foo
exists.
transformer
- The ClassFileTransformer which wraps using this prefix.prefix
- The prefix to apply to wrapped native methods when retrying a failed native method resolution. If prefix is either null
or the empty string, then failed native method resolutions are not retried for this transformer.NullPointerException
- if passed a null
transformer.UnsupportedOperationException
- if the current configuration of the JVM does not allow setting a native method prefix (isNativeMethodPrefixSupported()
is false).IllegalArgumentException
- if the transformer is not registered (see addTransformer
).void redefineModule(Module module, Set<Module> extraReads, Map<String,Set<Module>> extraExports, Map<String,Set<Module>> extraOpens, Set<Class<?>> extraUses, Map<Class<?>,List<Class<?>>> extraProvides)
This method cannot reduce the set of modules that a module reads, nor reduce the set of packages that it exports or opens, nor reduce the set of services that it uses or provides. This method is a no-op when invoked to redefine an unnamed module.
When expanding the services that a module uses or provides then the onus is on the agent to ensure that the service type will be accessible at each instrumentation site where the service type is used. This method does not check if the service type is a member of the module or in a package exported to the module by another module that it reads.
The extraExports
parameter is the map of additional packages to export. The extraOpens
parameter is the map of additional packages to open. In both cases, the map key is the fully-qualified name of the package as defined in section 6.5.3 of The Java Language Specification , for example,
"java.lang"
. The map value is the non-empty set of modules that the package should be exported or opened to.
The extraProvides
parameter is the additional service providers for the module to provide. The map key is the service type. The map value is the non-empty list of implementation types, each of which is a member of the module and an implementation of the service.
This method is safe for concurrent use and so allows multiple agents to instrument and update the same module at around the same time.
module
- the module to redefineextraReads
- the possibly-empty set of additional modules to readextraExports
- the possibly-empty map of additional packages to exportextraOpens
- the possibly-empty map of additional packages to openextraUses
- the possibly-empty set of additional services to useextraProvides
- the possibly-empty map of additional services to provideIllegalArgumentException
- If extraExports
or extraOpens
contains a key that is not a package in the module; if extraExports
or extraOpens
maps a key to an empty set; if a value in the extraProvides
map contains a service provider type that is not a member of the module or an implementation of the service; or extraProvides
maps a key to an empty listUnmodifiableModuleException
- if the module cannot be modifiedNullPointerException
- if any of the arguments are null
or any of the Sets or Maps contains a null
key or valueboolean isModifiableModule(Module module)
redefineModule
. If a module is modifiable then this method returns true
. If a module is not modifiable then this method returns false
. This method always returns true
when the module is an unnamed module (as redefining an unnamed module is a no-op).module
- the module to test if it can be modifiedtrue
if the module is modifiable, otherwise false
NullPointerException
- if the module is null
© 1993, 2023, Oracle and/or its affiliates. All rights reserved.
Documentation extracted from Debian's OpenJDK Development Kit package.
Licensed under the GNU General Public License, version 2, with the Classpath Exception.
Various third party code in OpenJDK is licensed under different licenses (see Debian package).
Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.
https://docs.oracle.com/en/java/javase/21/docs/api/java.instrument/java/lang/instrument/Instrumentation.html