Skip to content

Potential Memory Leak: Unbounded StringBuilder retention via ThreadLocal in EcsJsonSerializer #381

Description

@QiuYucheng2003

Describe the bug

There is a potential memory leak (Heap Exhaustion via Large Object Retention) caused by the improper reset of a ThreadLocal cached StringBuilder in co.elastic.logging.EcsJsonSerializer.

Root Cause

In EcsJsonSerializer.java, a ThreadLocal<StringBuilder> named messageStringBuilder is used to reuse StringBuilder instances to avoid allocations.

When retrieving the builder via getMessageStringBuilder(), the code calls result.setLength(0) to reset it. However, while setLength(0) resets the logical length, it does not shrink the underlying char[] capacity.

Impact

If an exceptionally large log message or a very deep exception stack trace (e.g., via formatThrowable) is serialized, the StringBuilder will expand its capacity significantly. In a typical thread-pool environment (e.g., Web container worker threads), these bloated StringBuilder objects will remain bound to long-living core threads permanently. Over time, this causes linear heap memory inflation and can eventually lead to an OutOfMemoryError (OOM).

Suggested Fix

Introduce a maximum capacity threshold when acquiring or releasing the StringBuilder. If the current capacity exceeds the threshold (e.g., 4096), discard the oversized builder and replace it with a newly allocated one.

Example fix in getMessageStringBuilder():

public static StringBuilder getMessageStringBuilder() {
    StringBuilder result = messageStringBuilder.get();
    if (result == null || result.capacity() > 4096) { // Add capacity check
        result = new StringBuilder(1024);
        messageStringBuilder.set(result);
    } else {
        result.setLength(0);
    }
    return result;
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent-javabugSomething isn't workingcommunityIssues and PRs created by the community

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions