[ 
https://issues.apache.org/jira/browse/CAMEL-10048?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Arseniy Tashoyan updated CAMEL-10048:
-------------------------------------
    Description: 
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 the 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.

  was:
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.


> 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 the 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)

Reply via email to