logging-log4j-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Remko Popma (JIRA)" <j...@apache.org>
Subject [jira] [Commented] (LOG4J2-1349) Garbage-free ThreadContext map
Date Sun, 26 Jun 2016 06:35:33 GMT

    [ https://issues.apache.org/jira/browse/LOG4J2-1349?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15350000#comment-15350000

Remko Popma commented on LOG4J2-1349:

About the worse performance: I think I did not present that well. True, garbage-free is not
_always_ better, but by a small margin and in rare cases. Perhaps I over-emphasized them in
the performance docs. Note that the garbage-free initiative has made Log4j 2.6 faster than
2.5 in all tests.

Overall, the feedback on Log4j going gc-free has been overwhelmingly positive, so I don't
think we are on the wrong track.

On the other hand, I understand that you want to keep complexity within reason. 

About my proposal, the problem here is that context key-value data can only be accessed as
a java.util.Map. For the stack, ThreadContext exposes the ContextStack interface, but the
equivalent ThreadContextMap SPI interface cannot be accessed from ThreadContext. 

I want to add a method {{getThreadContextMap()}} to ThreadContext, so that the context data
injector in LOG4J2-1010 can look like this:

public class DefaultContextDataInjector implements ContextDataInjector {
    public void injectContextData(final List<Property> properties, final LogEvent event)
        copyProperties(properties, event.getContextData());
        final ThreadContextMap contextMap = ThreadContext.getThreadContextMap(); // <--
the new method
        copyThreadContextMap(contextMap, event.getContextData());

    private void copyThreadContextMap(final ThreadContextMap contextMap,
            final ContextData<Object, Object> contextData) {

        if (contextMap instanceof IndexedMap) { // garbage-free
            IndexedMap<Object, Object> indexedMap = (IndexedMap<Object, Object>)
            for (int i = 0; i < indexedMap.size(); i++) {
                contextData.put(indexedMap.getKeyAt(i), indexedMap.getValueAt(i));
        } else { // classic
            final Map<String, String> map = contextMap.getImmutableMapOrNull();
            if (map != null) {
                for (Map.Entry<String, String> entry : map.entrySet()) {
                    contextData.put(entry.getKey(), entry.getValue());

    private void copyProperties(final List<Property> properties, final ContextData<Object,
Object> contextData) {
        if (properties != null) {
            for (int i = 0; i < properties.size(); i++) {
                final Property prop = properties.get(i);
                contextData.put(prop.getName(), prop.getValue());

interface IndexedMap<K, V> {
    int size();
    K getKeyAt(i);
    V getValueAt(i);

> Garbage-free ThreadContext map
> ------------------------------
>                 Key: LOG4J2-1349
>                 URL: https://issues.apache.org/jira/browse/LOG4J2-1349
>             Project: Log4j 2
>          Issue Type: Improvement
>          Components: API
>    Affects Versions: 2.5
>            Reporter: Remko Popma
>            Assignee: Remko Popma
>             Fix For: 2.7
> The current ThreadContext map and stack implementations allocate temporary objects. This
ticket is to investigate and track the work for alternative implementations that are garbage-free.
> Both DefaultThreadContextMap and DefaultThreadContextStack are copy-on-write data structures:
each modification replaces the ThreadLocal object with a modified copy. The advantage of this
approach is that there is no need to make a copy for each LogEvent.
> Also, DefaultThreadContextMap uses a JDK map, the JDK collections tend to allocate a
lot of temporary objects.

This message was sent by Atlassian JIRA

To unsubscribe, e-mail: log4j-dev-unsubscribe@logging.apache.org
For additional commands, e-mail: log4j-dev-help@logging.apache.org

View raw message