Working with Instrumentation
1. Understanding Java Agent Basics
| Concept | Detail |
|---|---|
| Agent | JAR with Premain-Class or Agent-Class |
| Premain | Loaded with -javaagent:agent.jar at startup |
| Agentmain | Attached at runtime via Attach API |
| Capability | Transform bytecode of loaded classes |
2. Creating Java Agents
Example: Premain agent
public class TimingAgent {
public static void premain(String args, Instrumentation inst) {
inst.addTransformer(new TimingTransformer(), true);
}
}
| Manifest Attr | Use |
|---|---|
| Premain-Class | Startup agents |
| Agent-Class | Runtime-attached |
| Can-Retransform-Classes | true to retransform |
| Can-Redefine-Classes | true to redefine |
3. Using Instrumentation API
| Method | Use |
|---|---|
addTransformer(t[, canRetransform]) | Register transformer |
retransformClasses(c...) | Re-apply transformers |
redefineClasses(defs...) | Replace class bytes |
getAllLoadedClasses() | Snapshot |
getObjectSize(obj) | Shallow size |
4. Transforming Classes (ClassFileTransformer)
Example: Transformer
class TimingTransformer implements ClassFileTransformer {
public byte[] transform(ClassLoader cl, String name, Class<?> classBeingRedefined,
ProtectionDomain pd, byte[] classfileBuffer) {
if (!name.startsWith("com/acme/")) return null;
return rewrite(classfileBuffer);
}
}
| Return | Meaning |
|---|---|
| null | No change |
| byte[] | Replacement bytecode |
5. Retransforming Classes
| Aspect | Detail |
|---|---|
| Restriction | Cannot add/remove fields, methods, supers |
| Use | Modify method bodies after load |
| Trigger | inst.retransformClasses(MyClass.class) |
6. Using Byte Buddy for Instrumentation
| API | Use |
|---|---|
new ByteBuddy().subclass(...) | Generate subclass |
AgentBuilder | Fluent transformer DSL |
Advice | Inject @OnMethodEnter/@OnMethodExit |
| Use | APM (New Relic, Datadog) |
7. Using ASM Library
| Component | Use |
|---|---|
| ClassReader | Parse bytecode |
| ClassWriter | Emit bytecode |
| ClassVisitor / MethodVisitor | Visitor pattern |
| Tree API | Higher-level node tree |
8. Attaching Agents at Runtime
Example: Attach API
VirtualMachine vm = VirtualMachine.attach(pid);
vm.loadAgent("/path/agent.jar", "options");
vm.detach();
| Aspect | Detail |
|---|---|
| Module | jdk.attach |
| Permission | Same UID; -XX:+EnableDynamicAgentLoading (Java 21+ warning) |
9. Profiling with Agents
| Tool | Mechanism |
|---|---|
| async-profiler | JVMTI + perf_events |
| YourKit / JProfiler | JVMTI agents |
| JFR | Built-in low-overhead |
| APM | Bytecode instrumentation via ByteBuddy |
10. Understanding Security Implications
Warning: Agents can read/modify any code, including security-sensitive classes. Treat agent JARs as fully trusted code. From Java 21, dynamic agent loading triggers a warning; future releases may require
-XX:+EnableDynamicAgentLoading.
| Risk | Mitigation |
|---|---|
| Tampering | Sign agent JARs, verify provenance |
| Performance | Measure overhead per transformer |
| Stability | Test transformations against all class shapes |