Skip to content

[Bug] Memory Leak via Unintended ThreadLocal (UTL) Misuse in ConstructorInstrumenter #60

@QiuYucheng2003

Description

@QiuYucheng2003

Description

There is a critical Unintended ThreadLocal (UTL) memory leak in the ConstructorInstrumenter class. The lastObject ThreadLocal is set but never cleared, leading to severe memory retention, especially in thread-pool environments.

Location

File: com.google.monitoring.runtime.instrumentation.ConstructorInstrumenter
Method: invokeSamplers(Object o)

Root Cause

In the invokeSamplers method, the newly allocated object is bound to the current thread:
lastObject.set(o);

However, there is no corresponding lastObject.remove() nor a try-finally block. If a registered sampler throws a RuntimeException, or even during normal method return, the object remains permanently strongly-referenced by the thread.

Impact

In high-throughput architectures using thread pools (e.g., APM agents in Flink workers), pooled threads will permanently hold onto these potentially large, short-lived object graphs. Over time, this causes severe memory spikes, premature promotion to the Old Gen, and catastrophic Full GC pauses.

Proposed Fix

Wrap the sampler execution in a try-finally block to ensure the ThreadLocal is safely cleared:

    lastObject.set(o);
    try {
      Class<?> currentClass = o.getClass();
      // ... existing traversal and sampler logic ...
    } finally {
      lastObject.remove();
    }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions