In my project, using ReusableMessageFactory create log message, which call
private static ThreadLocal<ReusableParameterizedMessage> threadLocalParameterized = new ThreadLocal<>();
private static ReusableParameterizedMessage getParameterized() {
ReusableParameterizedMessage result = threadLocalParameterized.get();
if (result == null) {
result = new ReusableParameterizedMessage();
threadLocalParameterized.set(result);
}
return result.reserved ? new ReusableParameterizedMessage().reserve() : result.reserve();
}
public static void release(final Message message) { // LOG4J2-1583
if (message instanceof Clearable) {
((Clearable) message).clear();
}
}
In the last line, result.reserved ? new ReusableParameterizedMessage().reserve() : result.reserve();, create too many ReusableParameterizedMessage which then create threadLocal and not call threadLocal.remove(), too may threadLocal exist.
In my memory dump, one tomcat thread have 155857 threadLocal entry where almost created by ReusableParameterizedMessage.buffer, occupy 125MB.
Two many threadLocal lead to frequently threadLoalMap hash conflict, ThreadLocalMap.getEntryAfterMiss() consuming excessive CPU time.
Usually logger.info() will call ReusableMessageFactory.release() set reserved to false, why create so many ReusableParameterizedMessage and buffer.
Below is Eclipse Memory Analyzer screen.
Is this normal? if not, how fix this?

After read log4j code, We did indeed misuse the
ReusableMessageFactory, our code :ReusableMessageFactory.newMessage()then need callReusableMessageFactory.release()to setreservedto false after log, bus we did not call.That's why wo have so many threadLocals.
Other:
ReusableParameterizedMessage.bufferremove static modifier, commit link