-
Notifications
You must be signed in to change notification settings - Fork 79
Description
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;
}