[QFJ-728] SessionState is leaking memory when dealing with resends and sequence numbers are skipped due to a SequenceReset Created: 05/Feb/13 Updated: 02/Apr/15 Resolved: 19/Dec/13 |
|
Status: | Closed |
Project: | QuickFIX/J |
Component/s: | Engine |
Affects Version/s: | 1.5.1, 1.5.3 |
Fix Version/s: | 1.6.0 |
Type: | Bug | Priority: | Critical |
Reporter: | Thilo-Alexander Ginkel | Assignee: | Christoph John |
Resolution: | Fixed | Votes: | 2 |
Labels: | None | ||
Environment: |
JDK 1.7 |
Description |
When QuickFIX/J has to deal with ResendRequests (e.g., due to sequence number gaps or exceptions thrown by the client), the SessionState.messageQueue will grow and fill up with entries until the ResendRequest has been fulfilled, but will never clean up these queue entries later. Eventually this will consume all available heap (if no disconnect happen in between, which would clear the queue) and cause an OOM. To reproduce this issue, subscribe to market data and raise an exception with a certain probability (e.g., every 100th message). Depending on the incoming message volume the messageQueue will fill up pretty quickly and won't release its content after the ResendRequest has been satisfied. |
Comments |
Comment by Thilo-Alexander Ginkel [ 05/Feb/13 ] |
Another user also blogged about this issue at: http://www.natesimpson.com/blog/archives/2011/06/15/quickfixj-and-odd-memory-leaks/ While making sure to never throw an exception solved this issue for the referenced case, it also happens for regular resends caused by a server-side issue or temporary network issues. |
Comment by Thilo-Alexander Ginkel [ 05/Feb/13 ] |
Just some further results of our investigation: This seems to be related to nextSequenceReset calling SessionState.setNextTargetMsgSeqNum, which causes the messages skipped by the SequenceReset to remain in the SessionState.messageQueue forever. |
Comment by Christoph John [ 05/Feb/13 ] |
Is this the same problem as described in |
Comment by Thilo-Alexander Ginkel [ 05/Feb/13 ] |
No, we are not seeing any StackOverflowErrors. It's just the SessionState.messageQueue that fills up which messages that will never be processed or garbage-collected. |
Comment by Christoph John [ 05/Feb/13 ] |
OK, I assume that |
Comment by Thilo-Alexander Ginkel [ 05/Feb/13 ] |
The messageQueue described in private final Map<Integer, Message> messageQueue = new LinkedHashMap<Integer, Message>(); At the moment I am no longer sure whether the SequenceReset handling implemented by QuickFIX/J is actually correct for GapFill mode. When a SequenceReset w/ GapFillFlag=Y and NewSeqNo is received, QuickFix/J will just set a new target msg sequence number (via setNextTargetMsgSeqNum), but completely ignores any messages it may have received with a lower sequence number. I'm not exactly sure whether those should be discarded or processed, but something needs to be done about them. |
Comment by Christoph John [ 19/Dec/13 ] |
Committed as http://sourceforge.net/p/quickfixj/code/1129/ In Session.nextSequenceReset(): make sure that all messages lower than the new seqnum are deleted from the message queue. |