Guillaume Nodet created CAMEL-23681:
---------------------------------------

             Summary: Optimize Exchange memory pressure: copy-on-write headers 
and lazy initialization
                 Key: CAMEL-23681
                 URL: https://issues.apache.org/jira/browse/CAMEL-23681
             Project: Camel
          Issue Type: Improvement
          Components: camel-core
            Reporter: Guillaume Nodet
             Fix For: 4.21.0


h2. Problem

During Exchange routing, message copies (multicast, splitter, recipient-list, 
pipeline processors) allocate new header maps via 
{{ConcurrentHashMap.putAll()}} on every copy. For high-fanout EIPs this creates 
significant memory pressure and GC load.

h2. Analysis

The Exchange lifecycle was analyzed for memory allocation patterns:

*Header Map Copying:*
- {{MessageSupport.copyFromWithNewBody()}} copies all headers on every message 
copy
- Multicast with N branches creates N full header map copies
- Splitter with 1000 items creates ~1000 header map copies
- Most copies only read headers — they never modify them

*Lazy Headers:*
- {{DefaultMessage.getHeader()}} and related read methods force-create the 
headers map even when headers have never been set
- Many pipeline processors only interact with the message body, not headers
- Each unnecessary map creation wastes 200-400 bytes

*Pooled Exchange Properties:*
- {{DefaultPooledExchange.done()}} discards and recreates the properties map on 
every reuse
- For typical small properties maps, clearing and reusing is cheaper than 
reallocating

h2. Solution

*1. Copy-on-Write Headers (Highest Impact)*

Message copies now share the headers map reference until one side modifies it. 
A {{CopyOnWriteHeadersMap}} wrapper defers cloning until the first mutation, 
with lazy iterators for {{keySet()}} and {{entrySet()}} that only trigger COW 
on {{Iterator.remove()}}.

*2. Lazy Headers Initialization*

{{getHeader()}} and related read methods return null without allocation when 
headers have never been set.

*3. Properties Map Reuse in Pooled Exchanges*

{{DefaultPooledExchange.done()}} reuses cleared properties maps instead of 
discarding them (threshold: 50 entries).

h2. Expected Impact

- Significant reduction in memory allocation for high-fanout EIPs (Multicast, 
Splitter, RecipientList)
- Zero behavioral change for existing routes
- Backward compatible: no public API changes



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to