Skip to content

Performance improvement to DefaultThreadContextMap #3935

@jengebr

Description

@jengebr

Description

HashMap.<init>(Map) is slow because it contains polymorphic calls to Map.entrySet(), Set.iterator(), Iterator.hasNext(), and Iterator.next(). These calls are megamorphic and the JIT cannot optimize them away, so the virtual method calls are quite expensive. I have attached a JMH test that demonstrates this general problem.

Profiling of multiple large, efficiency-critical applications shows that log4j contains one instance of this that is a hotspot in all of the applications: DefaultThreadContextMap.getCopy(). The call path is CloseableThreadContext$Instance.putAll() -> org.apache.logging.log4j.ThreadContext.getContext() -> org.apache.logging.log4j.spi.DefaultThreadContextMap.getCopy(). The line of code is return new HashMap<>(getMap(state));.

This can be trivially improved by unrolling the loop:

        Map<String, String> map = getMap(state);
        HashMap<String, String> copy = new HashMap<>((int)(map.size() * 1.35));
        for (Map.Entry<String, String> entry : map.entrySet()) {
        	copy.put(entry.getKey(), entry.getValue());
        }
        return copy;

Benchmark before:

Benchmark                                     (mapSize)  Mode  Cnt    Score   Error  Units
DefaultThreadContextMapCopyBenchmark.copyMap          5  avgt    5  271.915 ± 3.054  ns/op

Benchmark after:

Benchmark                                     (mapSize)  Mode  Cnt    Score   Error  Units
DefaultThreadContextMapCopyBenchmark.copyMap          5  avgt    5  129.784 ± 3.412  ns/op

Configuration

Logs

Reproduction

Two JMH tests attached, one showing the general effect and one demonstrating this opportunity.
DefaultThreadContextMapCopyBenchmark.java

HashMapConstructorBenchmark.java

Metadata

Metadata

Assignees

No one assigned

    Labels

    apiAffects the public APIperformanceIssues or PRs that affect performance, throughput, latency, etc.

    Type

    No type

    Projects

    Status

    To triage

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions