Dynamic Java Debugging Techniques and Java‑Agent Implementation

The article explains why production‑grade Java debugging must avoid stopping the JVM, then details Java‑Agent technology—including JVMTI, startup and runtime loading via the Attach mechanism—and shows how class redefinition and ASM‑based bytecode instrumentation can be combined in a TCP‑server tool to perform online fault isolation without pausing the application.

Meituan Technology Team
Meituan Technology Team
Meituan Technology Team
Dynamic Java Debugging Techniques and Java‑Agent Implementation

1. Why Dynamic Debugging Is Needed

Traditional breakpoint debugging pauses the application at the breakpoint, which is unacceptable for production services. This article introduces a Java dynamic debugging technique that avoids stopping the JVM, enabling online fault isolation.

2. Java Agent Technology

JVMTI (JVM Tool Interface) provides native access to the JVM. An Agent runs inside the target JVM and can be loaded either at JVM startup (via -javaagent) or at runtime.

2.1 Agent Implementation Modes

Before Java 5, an agent had to be written in native code. Since Java 5, the java.lang.instrument.Instrumentation API can be used:

public static void premain(String agentArgs, Instrumentation inst);
public static void agentmain(String agentArgs, Instrumentation inst);

The JVM first looks for premain. If it is not found, it searches for agentmain. Loading an agent at runtime requires implementing agentmain.

2.2 Loading the Agent at Startup

The agent JAR must declare Premain-Class or Agent-Class in its manifest. The JVM creates an AgentLibrary list and later invokes Agent_OnLoad for each entry.

2.3 Runtime Loading of an Agent

Runtime loading uses the Attach mechanism. The target JVM creates an Attach Listener thread that waits for a client connection. When a client sends a load command, the JVM loads the specified agent.

2.3.1 Attach Listener Initialization

The listener thread is started lazily. A SIGBREAK signal triggers its creation. The listener waits on a Unix socket (e.g., .java_pid<pid>) and processes commands from a queue.

2.3.2 Runtime Agent Loading Code

public static VirtualMachine attach(String pid) throws AttachNotSupportedException, IOException {
    // find a provider and call attachVirtualMachine(pid)
}

public VirtualMachine attachVirtualMachine(String pid) throws AttachNotSupportedException, IOException {
    int id = Integer.parseInt(pid);
    this.path = findSocketFile(id);
    if (this.path == null) {
        File attachFile = new File(tmpdir, ".attach_pid" + id);
        createAttachFile(attachFile.getPath());
        sendQuitTo(id);
        // wait for the socket file to appear
    }
    int socket = socket();
    connect(socket, this.path);
    return this;
}

2.3.3 The load Command

The load operation extracts the agent name, options and calls JvmtiExport.load_agent_library. If the agent is a Java instrumentation agent, the java.instrument module is loaded first.

static jint load_agent(AttachOperation* op, outputStream* out) {
    const char* agent = op->arg(0);
    const char* options = op->arg(2);
    if (strcmp(agent, "instrument") == 0) {
        // ensure java.instrument module is loaded
    }
    return JvmtiExport::load_agent_library(agent, absParam, options, out);
}

3. Class Redefinition (Dynamic Bytecode Replacement)

Instrumentation provides redefineClasses and retransformClasses. The JVM checks that the redefinition does not add, remove or rename fields/methods, nor change method signatures.

public void redefineClasses(ClassDefinition... definitions) throws ClassNotFoundException {
    if (!isRedefineClassesSupported()) {
        throw new UnsupportedOperationException("redefineClasses is not supported");
    }
    // argument validation omitted for brevity
    this.redefineClasses0(this.mNativeAgent, definitions);
}

private native void redefineClasses0(long agent, ClassDefinition[] definitions) throws ClassNotFoundException;

The native implementation forwards to JVMTI RedefineClasses, which performs:

Loading the new class bytes and merging constant pools.

Removing breakpoints.

De‑optimizing compiled code that depends on the class.

Updating vtables/itables and notifying the system dictionary.

4. Design of Java‑debug‑tool

Java‑debug‑tool

is a Java‑Agent that creates a TCP server inside the target JVM. Clients send debugging commands; the server instruments target classes with ASM, inserts “advice” code at entry, exit, field‑access, variable‑store, and exception points, and collects runtime data.

4.1 Architecture

Interaction Layer : translates user commands into a debugging protocol.

Connection Management Layer : handles client connections, time‑outs and cleanup.

Business Logic Layer : dispatches commands, performs bytecode enhancement, and processes results.

Foundation Layer : relies on java.lang.instrument.Instrumentation and JVMTI.

4.2 Bytecode Enhancement

ASM is used to insert probes. Each probe (advice) can be enabled/disabled per command, reducing overhead. Enhanced classes are cached; subsequent commands reuse the transformed bytecode. A lock is held per class to avoid concurrent conflicting enhancements.

4.3 Advice Execution Model

Advice runs inside the target JVM thread, collects data, and calls back to the server. If the collected data satisfies the command’s predicate, the advice is unloaded; otherwise it remains active for the next invocation.

4.4 Command Processing Flow

Commands go through three phases: pre‑processing (authentication, timestamping), execution (bytecode enhancement, advice registration, data collection), and post‑processing (resource release, connection cleanup). A two‑stage timeout mechanism aborts long‑running commands gracefully.

5. Summary

The article provides a comprehensive analysis of Java dynamic debugging, covering JVMTI, Java Agent loading (both at startup and at runtime), class redefinition, and a practical tool ( Java‑debug‑tool) that demonstrates how to apply these techniques for online fault isolation.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaInstrumentationAgentJVMTIdynamic debugging
Meituan Technology Team
Written by

Meituan Technology Team

Over 10,000 engineers powering China’s leading lifestyle services e‑commerce platform. Supporting hundreds of millions of consumers, millions of merchants across 2,000+ industries. This is the public channel for the tech teams behind Meituan, Dianping, Meituan Waimai, Meituan Select, and related services.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.