[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 QFJ-271 or QFJ-409?

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 QFJ-678 describes the messageQueue in question? Of course, having a bounded queue does not rectify the problem that the queue is not cleared after the ResendRequest has been satisfied.

Comment by Thilo-Alexander Ginkel [ 05/Feb/13 ]

The messageQueue described in QFJ-678 is indeed a different one. The messageQueue I refer to is not a LinkedBlockingQueue, but the LinkedHashMap referenced in quickfix.SessionState:

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.

Generated at Thu May 02 23:19:15 UTC 2024 using JIRA 7.5.2#75007-sha1:9f5725bb824792b3230a5d8716f0c13e296a3cae.