[
https://issues.apache.org/jira/browse/CAMEL-10048?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15326057#comment-15326057
]
Arseniy Tashoyan commented on CAMEL-10048:
------------------------------------------
How to fix?
I think, the best way is to remove this dangerous caching at all. There might
be a temptation to implement equals() and hashCode() methods in the helper
class AsyncProcessorConverterHelper.ProcessorToAsyncProcessorBridge in a way to
delegate both these calls to the processor wrapped by this class. However, the
root cause of the problem is the incorrect usage of a hash map. Key must
implement equals() and hashCode(). We cannot require all implementations of
Processor and RouteContext to implement these methods - it would be an
unmotivated bloating of their contracts with irrelevant functionality. Error
handlers in RoutingSlip are short-living objects, they shouldn't get into Old
Gen, so GC will clean them without significant performance overhead.
> Memory leak in RoutingSlip
> --------------------------
>
> Key: CAMEL-10048
> URL: https://issues.apache.org/jira/browse/CAMEL-10048
> Project: Camel
> Issue Type: Bug
> Components: camel-core
> Affects Versions: 2.16.2, 2.16.3, 2.17.0, 2.17.1
> Environment: java version "1.8.0_51"
> Java(TM) SE Runtime Environment (build 1.8.0_51-b16)
> Java HotSpot(TM) 64-Bit Server VM (build 25.51-b03, mixed mode)
> Reporter: Arseniy Tashoyan
> Labels: core, leak, routing
> Attachments: RoutingSlipMemoryLeakTest.java
>
> Original Estimate: 48h
> Remaining Estimate: 48h
>
> RoutingSlip has a cache of error handlers implemented as a ConcurrentHashMap.
> This map stores error handlers as values, and uses some synthetic objects as
> keys. For some kind of destinations provided in routing slip, map lookup
> operation does not work. Hence, new error handlers are always added to the
> map and existing error handlers never reused. Finally, the program runs out
> of memory.
> The synthetic keys are actually instances of class
> RoutingSlip.PreparedErrorHandler. Such key is based on two objects:
> RouteContext and destination Processor. Neither RouteContext nor Processor do
> not require their implementations to provide equals() and hashCode() methods.
> Strictly speaking, caching implementation in RoutingSlip is incorrect,
> because it uses hash map in the discouraged way. However, for some cases it
> works.
> The problem occurs when routing slip contains a 'sync' destination, in other
> words - destination is a Processor that does not implement AsyncProcessor
> interface. RoutingSlip determines destination producer via
> ProducerCache.doInAsyncProducer(), and the latter uses
> AsyncProcessorConverterHelper.convert() method. This method creates new
> instance of Processor for every processor that is not an instance of
> AsyncProcessor. This is where problem hides: new object has different hash
> code (defined by Object.hashCode()) and new object isn't equal to the object
> used as a key in the hash map (well, Object.equals()). Finally, new key for
> the hash map is calculated, lookup operation cannot find this key in the hash
> map, new key-value pair is put into the hash map.
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)