LOG4J2-1417 added internal representation that does not store non-JDK classes in ThreadLocals for safe use in web applications
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/83b930dc Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/83b930dc Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/83b930dc Branch: refs/heads/master Commit: 83b930dcf07fe68a8220c452a34cb2385525096b Parents: cff46e4 Author: rpopma <[email protected]> Authored: Sat Jun 11 17:20:51 2016 +0900 Committer: rpopma <[email protected]> Committed: Sat Jun 11 17:20:51 2016 +0900 ---------------------------------------------------------------------- .../org/apache/logging/log4j/util/Unbox.java | 46 +++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/83b930dc/log4j-api/src/main/java/org/apache/logging/log4j/util/Unbox.java ---------------------------------------------------------------------- diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/Unbox.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/Unbox.java index 137a702..d0bb16f 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/util/Unbox.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/Unbox.java @@ -52,6 +52,49 @@ public class Unbox { private static final int RINGBUFFER_SIZE = calculateRingBufferSize("log4j.unbox.ringbuffer.size"); private static final int MASK = RINGBUFFER_SIZE - 1; + /** + * State implementation that only puts JDK classes in ThreadLocals, so this is safe to be used from + * web applications. Web application containers have thread pools that may hold on to ThreadLocal objects + * after the application was stopped. This may prevent the classes of the application from being unloaded, + * causing memory leaks. + * <p> + * Such memory leaks will not occur if only JDK classes are stored in ThreadLocals. + * </p> + */ + private static class WebSafeState { + private final ThreadLocal<StringBuilder[]> ringBuffer = new ThreadLocal<>(); + private final ThreadLocal<int[]> current = new ThreadLocal<>(); + + public StringBuilder getStringBuilder() { + StringBuilder[] array = ringBuffer.get(); + if (array == null) { + array = new StringBuilder[RINGBUFFER_SIZE]; + for (int i = 0; i < array.length; i++) { + array[i] = new StringBuilder(21); + } + ringBuffer.set(array); + current.set(new int[1]); + } + int[] index = current.get(); + final StringBuilder result = array[MASK & index[0]++]; + result.setLength(0); + return result; + } + + public boolean isBoxedPrimitive(final StringBuilder text) { + StringBuilder[] array = ringBuffer.get(); + if (array == null) { + return false; + } + for (int i = 0; i < array.length; i++) { + if (text == array[i]) { + return true; + } + } + return false; + } + } + private static class State { private final StringBuilder[] ringBuffer = new StringBuilder[RINGBUFFER_SIZE]; private int current; @@ -77,6 +120,7 @@ public class Unbox { } } private static ThreadLocal<State> threadLocalState = new ThreadLocal<>(); + private static WebSafeState webSafeState = new WebSafeState(); private Unbox() { // this is a utility @@ -218,7 +262,7 @@ public class Unbox { } private static StringBuilder getSB() { - return getState().getStringBuilder(); + return Constants.ENABLE_THREADLOCALS ? getState().getStringBuilder() : webSafeState.getStringBuilder(); } /** For testing. */
