JVMTM Tool Interface

Version 20.0


What is the JVM Tool Interface?

The JVMTM Tool Interface (JVM TI) is a programming interface used by development and monitoring tools. It provides both a way to inspect the state and to control the execution of applications running in the JavaTM virtual machine (VM).
JVM TI is intended to provide a VM interface for the full breadth of tools that need access to VM state, including but not limited to: profiling, debugging, monitoring, thread analysis, and coverage analysis tools.
JVM TI may not be available in all implementations of the JavaTM virtual machine.
JVM TI is a two-way interface. A client of JVM TI, hereafter called an agent, can be notified of interesting occurrences through events. JVM TI can query and control the application through many functions, either in response to events or independent of them.
Agents run in the same process with and communicate directly with the virtual machine executing the application being examined. This communication is through a native interface (JVM TI). The native in-process interface allows maximal control with minimal intrusion on the part of a tool. Typically, agents are relatively compact. They can be controlled by a separate process which implements the bulk of a tool's function without interfering with the target application's normal execution.

Architecture

Tools can be written directly to JVM TI or indirectly through higher level interfaces. The Java Platform Debugger Architecture includes JVM TI, but also contains higher-level, out-of-process debugger interfaces. The higher-level interfaces are more appropriate than JVM TI for many tools. For more information on the Java Platform Debugger Architecture, see the Java Platform Debugger Architecture website.

Writing Agents

Agents can be written in any native language that supports C language calling conventions and C or C++ definitions.
The function, event, data type, and constant definitions needed for using JVM TI are defined in the include file jvmti.h. To use these definitions add the J2SETM include directory to your include path and add
#include <jvmti.h>
    
to your source code.

Deploying Agents

An agent is deployed in a platform specific manner but is typically the platform equivalent of a dynamic library. On the WindowsTM operating system, for example, an agent library is a "Dynamic Linked Library" (DLL). On LinuxTM Operating Environment, an agent library is a shared object (.so file).
An agent may be started at VM startup by specifying the agent library name using a command line option. Some implementations may support a mechanism to start agents in the live phase. The details of how this is initiated are implementation specific.

Statically Linked Agents (since version 1.2.3)

A native JVMTI Agent may be statically linked with the VM. The manner in which the library and VM image are combined is implementation-dependent. An agent L whose image has been combined with the VM is defined as statically linked if and only if the agent exports a function called Agent_OnLoad_L.
If a statically linked agent L exports a function called Agent_OnLoad_L and a function called Agent_OnLoad, the Agent_OnLoad function will be ignored. If an agent L is statically linked, an Agent_OnLoad_L function will be invoked with the same arguments and expected return value as specified for the Agent_OnLoad function. An agent L that is statically linked will prohibit an agent of the same name from being loaded dynamically.
The VM will invoke the Agent_OnUnload_L function of the agent, if such a function is exported, at the same point during VM execution as it would have called the dynamic entry point Agent_OnUnLoad. A statically loaded agent cannot be unloaded. The Agent_OnUnload_L function will still be called to do any other agent shutdown related tasks. If a statically linked agent L exports a function called Agent_OnUnLoad_L and a function called Agent_OnUnLoad, the Agent_OnUnLoad function will be ignored.
If an agent L is statically linked, an Agent_OnAttach_L function will be invoked with the same arguments and expected return value as specified for the Agent_OnAttach function. If a statically linked agent L exports a function called Agent_OnAttach_L and a function called Agent_OnAttach, the Agent_OnAttach function will be ignored.

Agent Command Line Options

The term "command-line option" is used below to mean options supplied in the JavaVMInitArgs argument to the JNI_CreateJavaVM function of the JNI Invocation API.
One of the two following command-line options is used on VM startup to properly load and run agents. These arguments identify the library containing the agent as well as an options string to be passed in at startup.
-agentlib:<agent-lib-name>=<options>
The name following -agentlib: is the name of the library to load. Lookup of the library, both its full name and location, proceeds in a platform-specific manner. Typically, the <agent-lib-name> is expanded to an operating system specific file name. The <options> will be passed to the agent on start-up. For example, if the option -agentlib:foo=opt1,opt2 is specified, the VM will attempt to load the shared library foo.dll from the system PATH under WindowsTM or libfoo.so from the LD_LIBRARY_PATH under LinuxTM . If the agent library is statically linked into the executable then no actual loading takes place.
-agentpath:<path-to-agent>=<options>
The path following -agentpath: is the absolute path from which to load the library. No library name expansion will occur. The <options> will be passed to the agent on start-up. For example, if the option -agentpath:c:\myLibs\foo.dll=opt1,opt2 is specified, the VM will attempt to load the shared library c:\myLibs\foo.dll. If the agent library is statically linked into the executable then no actual loading takes place.
For a dynamic shared library agent, the start-up routine Agent_OnLoad in the library will be invoked. If the agent library is statically linked into the executable then the system will attempt to invoke the Agent_OnLoad_<agent-lib-name> entry point where <agent-lib-name> is the basename of the agent. In the above example -agentpath:c:\myLibs\foo.dll=opt1,opt2, the system will attempt to find and call the Agent_OnLoad_foo start-up routine.
Libraries loaded with -agentlib: or -agentpath: will be searched for JNI native method implementations to facilitate the use of Java programming language code in tools, as is needed for bytecode instrumentation.
The agent libraries will be searched after all other libraries have been searched (agents wishing to override or intercept the native method implementations of non-agent methods can use the NativeMethodBind event).
These switches do the above and nothing more - they do not change the state of the VM or JVM TI. No command line options are needed to enable JVM TI or aspects of JVM TI, this is handled programmatically by the use of capabilities.

Agent Start-Up

The VM starts each agent by invoking a start-up function. If the agent is started in the OnLoad phase the function Agent_OnLoad or Agent_OnLoad_L for statically linked agents will be invoked. If the agent is started in the live phase the function Agent_OnAttach or Agent_OnAttach_L for statically linked agents will be invoked. Exactly one call to a start-up function is made per agent.

Agent Start-Up (OnLoad phase)

If an agent is started during the OnLoad phase then its agent library must export a start-up function with the following prototype:
JNIEXPORT jint JNICALL
Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
Or for a statically linked agent named 'L':
JNIEXPORT jint JNICALL
Agent_OnLoad_L(JavaVM *vm, char *options, void *reserved)
The VM will start the agent by calling this function. It will be called early enough in VM initialization that:
The VM will call the Agent_OnLoad or Agent_OnLoad_<agent-lib-name> function with <options> as the second argument - that is, using the command-line option examples, "opt1,opt2" will be passed to the char *options argument of Agent_OnLoad. The options argument is encoded as a modified UTF-8 string. If =<options> is not specified, a zero length string is passed to options. The lifespan of the options string is the Agent_OnLoad or Agent_OnLoad_<agent-lib-name> call. If needed beyond this time the string or parts of the string must be copied. The period between when Agent_OnLoad is called and when it returns is called the OnLoad phase. Since the VM is not initialized during the OnLoad phase, the set of allowed operations inside Agent_OnLoad is restricted (see the function descriptions for the functionality available at this time). The agent can safely process the options and set event callbacks with SetEventCallbacks. Once the VM initialization event is received (that is, the VMInit callback is invoked), the agent can complete its initialization.

Rationale: Early startup is required so that agents can set the desired capabilities, many of which must be set before the VM is initialized. In JVMDI, the -Xdebug command-line option provided very coarse-grain control of capabilities. JVMPI implementations use various tricks to provide a single "JVMPI on" switch. No reasonable command-line option could provide the fine-grain of control required to balance needed capabilities vs performance impact. Early startup is also needed so that agents can control the execution environment - modifying the file system and system properties to install their functionality.

The return value from Agent_OnLoad or Agent_OnLoad_<agent-lib-name> is used to indicate an error. Any value other than zero indicates an error and causes termination of the VM.

Agent Start-Up (Live phase)

A VM may support a mechanism that allows agents to be started in the VM during the live phase. The details of how this is supported, are implementation specific. For example, a tool may use some platform specific mechanism, or implementation specific API, to attach to the running VM, and request it start a given agent.
If an agent is started during the live phase then its agent library must export a start-up function with the following prototype:
JNIEXPORT jint JNICALL
Agent_OnAttach(JavaVM* vm, char *options, void *reserved)
Or for a statically linked agent named 'L':
JNIEXPORT jint JNICALL
Agent_OnAttach_L(JavaVM* vm, char *options, void *reserved)
The VM will start the agent by calling this function. It will be called in the context of a thread that is attached to the VM. The first argument <vm> is the Java VM. The <options> argument is the startup options provided to the agent. <options> is encoded as a modified UTF-8 string. If startup options were not provided, a zero length string is passed to options. The lifespan of the options string is the Agent_OnAttach or Agent_OnAttach_<agent-lib-name> call. If needed beyond this time the string or parts of the string must be copied.
Note that some capabilities may not be available in the live phase.
The Agent_OnAttach or Agent_OnAttach_<agent-lib-name > function initializes the agent and returns a value to the VM to indicate if an error occurred. Any value other than zero indicates an error. An error does not cause the VM to terminate. Instead the VM ignores the error, or takes some implementation specific action -- for example it might print an error to standard error, or record the error in a system log.

Agent Shutdown

The library may optionally export a shutdown function with the following prototype:
JNIEXPORT void JNICALL
Agent_OnUnload(JavaVM *vm)
Or for a statically linked agent named 'L':
JNIEXPORT void JNICALL
Agent_OnUnload_L(JavaVM *vm)
This function will be called by the VM when the library is about to be unloaded. The library will be unloaded (unless it is statically linked into the executable) and this function will be called if some platform specific mechanism causes the unload (an unload mechanism is not specified in this document) or the library is (in effect) unloaded by the termination of the VM. VM termination includes normal termination and VM failure, including start-up failure, but not, of course, uncontrolled shutdown. An implementation may also choose to not call this function if the Agent_OnAttach/ Agent_OnAttach_L function reported an error (returned a non-zero value). Note the distinction between this function and the VM Death event: for the VM Death event to be sent, the VM must have run at least to the point of initialization and a valid JVM TI environment must exist which has set a callback for VMDeath and enabled the event. None of these are required for Agent_OnUnload or Agent_OnUnload_<agent-lib-name> and this function is also called if the library is unloaded for other reasons. In the case that a VM Death event is sent, it will be sent before this function is called (assuming this function is called due to VM termination). This function can be used to clean-up resources allocated by the agent.

JAVA_TOOL_OPTIONS

Since the command-line cannot always be accessed or modified, for example in embedded VMs or simply VMs launched deep within scripts, a JAVA_TOOL_OPTIONS variable is provided so that agents may be launched in these cases.
Platforms which support environment variables or other named strings, may support the JAVA_TOOL_OPTIONS variable. This variable will be broken into options at white-space boundaries. White-space characters include space, tab, carriage-return, new-line, vertical-tab, and form-feed. Sequences of white-space characters are considered equivalent to a single white-space character. No white-space is included in the options unless quoted. Quoting is as follows: JNI_CreateJavaVM (in the JNI Invocation API) will prepend these options to the options supplied in its JavaVMInitArgs argument. Platforms may disable this feature in cases where security is a concern; for example, the Reference Implementation disables this feature on Unix systems when the effective user or group ID differs from the real ID. This feature is intended to support the initialization of tools -- specifically including the launching of native or Java programming language agents. Multiple tools may wish to use this feature, so the variable should not be overwritten, instead, options should be appended to the variable. Note that since the variable is processed at the time of the JNI Invocation API create VM call, options processed by a launcher (e.g., VM selection options) will not be handled.

Environments

The JVM TI specification supports the use of multiple simultaneous JVM TI agents. Each agent has its own JVM TI environment. That is, the JVM TI state is separate for each agent - changes to one environment do not affect the others. The state of a JVM TI environment includes: Although their JVM TI state is separate, agents inspect and modify the shared state of the VM, they also share the native environment in which they execute. As such, an agent can perturb the results of other agents or cause them to fail. It is the responsibility of the agent writer to specify the level of compatibility with other agents. JVM TI implementations are not capable of preventing destructive interactions between agents. Techniques to reduce the likelihood of these occurrences are beyond the scope of this document.
An agent creates a JVM TI environment by passing a JVM TI version as the interface ID to the JNI Invocation API function GetEnv. See Accessing JVM TI Functions for more details on the creation and use of JVM TI environments. Typically, JVM TI environments are created by calling GetEnv from Agent_OnLoad.

Bytecode Instrumentation

This interface does not include some events that one might expect in an interface with profiling support. Some examples include full speed method enter and exit events. The interface instead provides support for bytecode instrumentation, the ability to alter the Java virtual machine bytecode instructions which comprise the target program. Typically, these alterations are to add "events" to the code of a method - for example, to add, at the beginning of a method, a call to MyProfiler.methodEntered(). Since the changes are purely additive, they do not modify application state or behavior. Because the inserted agent code is standard bytecodes, the VM can run at full speed, optimizing not only the target program but also the instrumentation. If the instrumentation does not involve switching from bytecode execution, no expensive state transitions are needed. The result is high performance events. This approach also provides complete control to the agent: instrumentation can be restricted to "interesting" portions of the code (e.g., the end user's code) and can be conditional. Instrumentation can run entirely in Java programming language code or can call into the native agent. Instrumentation can simply maintain counters or can statistically sample events.
Instrumentation can be inserted in one of three ways:
The class modification functionality provided in this interface is intended to provide a mechanism for instrumentation (the ClassFileLoadHook event and the RetransformClasses function) and, during development, for fix-and-continue debugging (the RedefineClasses function).
Care must be taken to avoid perturbing dependencies, especially when instrumenting core classes. For example, an approach to getting notification of every object allocation is to instrument the constructor on Object. Assuming that the constructor is initially empty, the constructor could be changed to:
      public Object() {
        MyProfiler.allocationTracker(this);
      }
    
However, if this change was made using the ClassFileLoadHook event then this might impact a typical VM as follows: the first created object will call the constructor causing a class load of MyProfiler; which will then cause object creation, and since MyProfiler isn't loaded yet, infinite recursion; resulting in a stack overflow. A refinement of this would be to delay invoking the tracking method until a safe time. For example, trackAllocations could be set in the handler for the VMInit event.
      static boolean trackAllocations = false;

      public Object() {
        if (trackAllocations) {
          MyProfiler.allocationTracker(this);
        }
      }
    
The SetNativeMethodPrefix allows native methods to be instrumented by the use of wrapper methods.

Bytecode Instrumentation of code in modules

Agents can use the functions AddModuleReads, AddModuleExports, AddModuleOpens, AddModuleUses and AddModuleProvides to update a module to expand the set of modules that it reads, the set of packages that it exports or opens to other modules, or the services that it uses and provides.
As an aid to agents that deploy supporting classes on the search path of the bootstrap class loader, or the search path of the class loader that loads the main class, the Java virtual machine arranges for the module of classes transformed by the ClassFileLoadHook event to read the unnamed module of both class loaders.

Modified UTF-8 String Encoding

JVM TI uses modified UTF-8 to encode character strings. This is the same encoding used by JNI. Modified UTF-8 differs from standard UTF-8 in the representation of supplementary characters and of the null character. See the Modified UTF-8 Strings section of the JNI specification for details.

Specification Context

Since this interface provides access to the state of applications running in the Java virtual machine; terminology refers to the Java platform and not the native platform (unless stated otherwise). For example:
Sun, Sun Microsystems, the Sun logo, Java, and JVM are trademarks or registered trademarks of Oracle and/or its affiliates, in the U.S. and other countries.


Functions

Accessing Functions

Native code accesses JVM TI features by calling JVM TI functions. Access to JVM TI functions is by use of an interface pointer in the same manner as Java Native Interface (JNI) functions are accessed. The JVM TI interface pointer is called the environment pointer.
An environment pointer is a pointer to an environment and has the type jvmtiEnv*. An environment has information about its JVM TI connection. The first value in the environment is a pointer to the function table. The function table is an array of pointers to JVM TI functions. Every function pointer is at a predefined offset inside the array.
When used from the C language: double indirection is used to access the functions; the environment pointer provides context and is the first parameter of each function call; for example:
jvmtiEnv *jvmti;
...
jvmtiError err = (*jvmti)->GetLoadedClasses(jvmti, &class_count, &classes);
    
When used from the C++ language: functions are accessed as member functions of jvmtiEnv; the environment pointer is not passed to the function call; for example:
jvmtiEnv *jvmti;
...
jvmtiError err = jvmti->GetLoadedClasses(&class_count, &classes);
    
Unless otherwise stated, all examples and declarations in this specification use the C language.
A JVM TI environment can be obtained through the JNI Invocation API GetEnv function:
jvmtiEnv *jvmti;
...
(*jvm)->GetEnv(jvm, &jvmti, JVMTI_VERSION_1_0);
    
Each call to GetEnv creates a new JVM TI connection and thus a new JVM TI environment. The version argument of GetEnv must be a JVM TI version. The returned environment may have a different version than the requested version but the returned environment must be compatible. GetEnv will return JNI_EVERSION if a compatible version is not available, if JVM TI is not supported or JVM TI is not supported in the current VM configuration. Other interfaces may be added for creating JVM TI environments in specific contexts. Each environment has its own state (for example, desired events, event handling functions, and capabilities). An environment is released with DisposeEnvironment. Thus, unlike JNI which has one environment per thread, JVM TI environments work across threads and are created dynamically.

Function Return Values

JVM TI functions always return an error code via the jvmtiError function return value. Some functions can return additional values through pointers provided by the calling function. In some cases, JVM TI functions allocate memory that your program must explicitly deallocate. This is indicated in the individual JVM TI function descriptions. Empty lists, arrays, sequences, etc are returned as NULL.
In the event that the JVM TI function encounters an error (any return value other than JVMTI_ERROR_NONE) the values of memory referenced by argument pointers is undefined, but no memory will have been allocated and no global references will have been allocated. If the error occurs because of invalid input, no action will have occurred.

Managing JNI Object References

JVM TI functions identify objects with JNI references (jobject and jclass) and their derivatives (jthread and jthreadGroup). References passed to JVM TI functions can be either global or local, but they must be strong references. All references returned by JVM TI functions are local references--these local references are created during the JVM TI call. Local references are a resource that must be managed (see the JNI Documentation). When threads return from native code all local references are freed. Note that some threads, including typical agent threads, will never return from native code. A thread is ensured the ability to create sixteen local references without the need for any explicit management. For threads executing a limited number of JVM TI calls before returning from native code (for example, threads processing events), it may be determined that no explicit management is needed. However, long running agent threads will need explicit local reference management--usually with the JNI functions PushLocalFrame and PopLocalFrame. Conversely, to preserve references beyond the return from native code, they must be converted to global references. These rules do not apply to jmethodID and jfieldID as they are not jobjects.

Prerequisite State for Calling Functions

Unless the function explicitly states that the agent must bring a thread or the VM to a particular state (for example, suspended), the JVM TI implementation is responsible for bringing the VM to a safe and consistent state for performing the function.

Exceptions and Functions

JVM TI functions never throw exceptions; error conditions are communicated via the function return value. Any existing exception state is preserved across a call to a JVM TI function. See the Java Exceptions section of the JNI specification for information on handling exceptions.

Function Index