This is an automated email from the ASF dual-hosted git repository.
ckozak pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
The following commit(s) were added to refs/heads/master by this push:
new 8504933 LOG4J2-2752: MutableLogEvent and RingBufferLogEvent lazily
create buffers
8504933 is described below
commit 8504933502bd9e6cf801968adda4c85532a0ea7b
Author: Carter Kozak <[email protected]>
AuthorDate: Mon Dec 30 17:12:11 2019 -0500
LOG4J2-2752: MutableLogEvent and RingBufferLogEvent lazily create buffers
When reusable events are used with non-reusable message implementations
(ParameterizedMessageFactory) there's no need to create these buffers.
---
.../log4j/core/async/RingBufferLogEvent.java | 31 +++++++++++-----------
.../logging/log4j/core/impl/MutableLogEvent.java | 16 +++++------
.../log4j/core/impl/MutableLogEventTest.java | 5 ++++
src/changes/changes.xml | 3 +++
4 files changed, 29 insertions(+), 26 deletions(-)
diff --git
a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java
b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java
index 030ce56..0434eb6 100644
---
a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java
+++
b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java
@@ -60,12 +60,7 @@ public class RingBufferLogEvent implements LogEvent,
ReusableMessage, CharSequen
@Override
public RingBufferLogEvent newInstance() {
- final RingBufferLogEvent result = new RingBufferLogEvent();
- if (Constants.ENABLE_THREADLOCALS) {
- result.messageText = new
StringBuilder(Constants.INITIAL_REUSABLE_MESSAGE_SIZE);
- result.parameters = new Object[10];
- }
- return result;
+ return new RingBufferLogEvent();
}
}
@@ -134,10 +129,8 @@ public class RingBufferLogEvent implements LogEvent,
ReusableMessage, CharSequen
final ReusableMessage reusable = (ReusableMessage) msg;
reusable.formatTo(getMessageTextForWriting());
messageFormat = reusable.getFormat();
- if (parameters != null) {
- parameters = reusable.swapParameters(parameters);
- parameterCount = reusable.getParameterCount();
- }
+ parameters = reusable.swapParameters(parameters == null ? new
Object[10] : parameters);
+ parameterCount = reusable.getParameterCount();
} else {
this.message = InternalAsyncUtil.makeMessageImmutable(msg);
}
@@ -145,8 +138,8 @@ public class RingBufferLogEvent implements LogEvent,
ReusableMessage, CharSequen
private StringBuilder getMessageTextForWriting() {
if (messageText == null) {
- // Should never happen:
- // only happens if user logs a custom reused message when
Constants.ENABLE_THREADLOCALS is false
+ // Happens the first time messageText is requested or if a user
logs
+ // a custom reused message when Constants.ENABLE_THREADLOCALS is
false
messageText = new
StringBuilder(Constants.INITIAL_REUSABLE_MESSAGE_SIZE);
}
messageText.setLength(0);
@@ -412,12 +405,18 @@ public class RingBufferLogEvent implements LogEvent,
ReusableMessage, CharSequen
}
// ensure that excessively long char[] arrays are not kept in memory
forever
- StringBuilders.trimToMaxSize(messageText,
Constants.MAX_REUSABLE_MESSAGE_SIZE);
+ if (Constants.ENABLE_THREADLOCALS) {
+ StringBuilders.trimToMaxSize(messageText,
Constants.MAX_REUSABLE_MESSAGE_SIZE);
- if (parameters != null) {
- for (int i = 0; i < parameters.length; i++) {
- parameters[i] = null;
+ if (parameters != null) {
+ Arrays.fill(parameters, null);
}
+ } else {
+ // A user may have manually logged a ReusableMessage
implementation, when thread locals are
+ // disabled we remove the reference in order to avoid permanently
holding references to these
+ // buffers.
+ messageText = null;
+ parameters = null;
}
}
diff --git
a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
index e38afae..7674491 100644
---
a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
+++
b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
@@ -69,7 +69,8 @@ public class MutableLogEvent implements LogEvent,
ReusableMessage, ParameterVisi
transient boolean reserved = false;
public MutableLogEvent() {
- this(new StringBuilder(Constants.INITIAL_REUSABLE_MESSAGE_SIZE), new
Object[10]);
+ // messageText and the parameter array are lazily initialized
+ this(null, null);
}
public MutableLogEvent(final StringBuilder msgText, final Object[]
replacementParameters) {
@@ -148,9 +149,7 @@ public class MutableLogEvent implements LogEvent,
ReusableMessage, ParameterVisi
StringBuilders.trimToMaxSize(messageText,
Constants.MAX_REUSABLE_MESSAGE_SIZE);
if (parameters != null) {
- for (int i = 0; i < parameters.length; i++) {
- parameters[i] = null;
- }
+ Arrays.fill(parameters, null);
}
// primitive fields that cannot be cleared:
@@ -214,10 +213,8 @@ public class MutableLogEvent implements LogEvent,
ReusableMessage, ParameterVisi
final ReusableMessage reusable = (ReusableMessage) msg;
reusable.formatTo(getMessageTextForWriting());
this.messageFormat = msg.getFormat();
- if (parameters != null) {
- parameters = reusable.swapParameters(parameters);
- parameterCount = reusable.getParameterCount();
- }
+ parameters = reusable.swapParameters(parameters == null ? new
Object[10] : parameters);
+ parameterCount = reusable.getParameterCount();
} else {
this.message = InternalAsyncUtil.makeMessageImmutable(msg);
}
@@ -225,8 +222,7 @@ public class MutableLogEvent implements LogEvent,
ReusableMessage, ParameterVisi
private StringBuilder getMessageTextForWriting() {
if (messageText == null) {
- // Should never happen:
- // only happens if user logs a custom reused message when
Constants.ENABLE_THREADLOCALS is false
+ // Happens the first time messageText is requested
messageText = new
StringBuilder(Constants.INITIAL_REUSABLE_MESSAGE_SIZE);
}
messageText.setLength(0);
diff --git
a/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java
b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java
index a1f4f91..7e94ca6 100644
---
a/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java
+++
b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java
@@ -31,6 +31,7 @@ import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.message.ParameterizedMessage;
import org.apache.logging.log4j.message.ReusableMessageFactory;
+import org.apache.logging.log4j.message.ReusableSimpleMessage;
import org.apache.logging.log4j.message.SimpleMessage;
import org.apache.logging.log4j.util.FilteredObjectInputStream;
import org.apache.logging.log4j.util.SortedArrayStringMap;
@@ -189,6 +190,10 @@ public class MutableLogEventTest {
@Test
public void testClear() {
final MutableLogEvent mutable = new MutableLogEvent();
+ // initialize the event with an empty message
+ ReusableSimpleMessage simpleMessage = new ReusableSimpleMessage();
+ simpleMessage.set("");
+ mutable.setMessage(simpleMessage);
assertEquals("context data", 0, mutable.getContextData().size());
assertNull("context stack", mutable.getContextStack());
assertFalse("end of batch", mutable.isEndOfBatch());
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 92222b6..3bc396f 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -193,6 +193,9 @@
<action issue="LOG4J2-2751" dev="ckozak" type="fix">
Fix StackLocator.getCallerClass performance in cases where
Reflection.getCallerClass is not accessible.
</action>
+ <action issue="LOG4J2-2752" dev="ckozak" type="fix">
+ MutableLogEvent and RingBufferLogEvent avoid StringBuffer and
parameter array allocation unless reusable messages are used.
+ </action>
</release>
<release version="2.13.0" date="2019-12-11" description="GA Release
2.13.0">
<action issue="LOG4J2-2058" dev="rgoers" type="fix">