I am coding a Forex Trading robot, and I am running an outOfMemory exception after some time (around 2 hours) using BlockingCollection. I basically have 1 queue pair Trade chart, that are added into a dict:
private Dictionary<string, BlockingCollection<tick>> tickQueues = new Dictionary<string, BlockingCollection<tick>>();
I check the memory dump after one hour, and I can see the following items are piling up:
Count Size(bytes) Inclusive Size
ThreadPoolWorkQueue+QueueSegment 22,951 24,236,256 40,316,868
QueueUserWorkItemCallback 689,838 13,796,760 16,081,272
TimerQueueTimer 11,160 713,772 2,355,736
I have a timer that is responsible to add data to the Queue:
private void TickTimer_tick(object source, ElapsedEventArgs e) {
if (Monitor.TryEnter(LockTimerTick, GlobalSettings.APISleepDelayMSTick)) {
updateLockFailCount = 0;
try {
tick t = new tick(DateTime.Now, d.bid, d.ask);
lastBid = d.bid;
lastAsk = d.ask;
t.pair = Inst.pair;
//myTickQueue.TryAdd(t);
if (!myTickQueue.TryAdd(t)) {
functions.Logger.log("Error when adding Tick on Queue for " + Inst.pair+ " Maybe Queue is full", "SHMAPI", LOGLEVEL.WARN);
}
} catch (Exception E) {
functions.Logger.log("Error happened when refreshing tick data: " + E.Message, "SHMAPI", LOGLEVEL.ERROR);
} finally {
Monitor.Exit(LockTimerTick);
}
} else {
updateLockFailCount++;
int sev = LOGLEVEL.TRACE;
if (updateLockFailCount == 10) { sev = LOGLEVEL.DEBUG; }
if (updateLockFailCount==50) { sev = LOGLEVEL.WARN; }
if (updateLockFailCount % 100 == 0 && updateLockFailCount>=100) { sev = LOGLEVEL.ERROR; }
functions.Logger.log("Could not get lock to refresh tick data for symbol "+Symbol, "SHMAPI", sev);
}
}
And finally, my task that checks the Q:
public void startQueueTask(string Pair) {
if (!tickQueues.ContainsKey(Pair.ToUpper())) {
tickQueues.Add(Pair.ToUpper(), new BlockingCollection<tick>(GlobalSettings.tickQueueSize));
if (!MTAPIs.ContainsKey(Pair.ToUpper())) {
throw new Exception("API for pair " + Pair + " Should be initialized !!");
}
MTAPIs[Pair.ToUpper()].setTickQueue(tickQueues[Pair.ToUpper()]);
functions.Logger.log("Starting " + Pair + " Queue Task", "TICKPROCESSING", LOGLEVEL.DEBUG);
Task.Run(() => {
foreach (tick tick in tickQueues[Pair.ToUpper()].GetConsumingEnumerable()) {
try {
onTick(tick);
} catch (Exception E) {
functions.Logger.log("Error processing tick for symbol " + tick.pair + " " + E.Message, "TICKPROCESSING", LOGLEVEL.ERROR);
functions.printException(E);
}
}
functions.Logger.log("Exiting Queue Task", "TICKPROCESSING", LOGLEVEL.ERROR);
});
} else {
functions.Logger.log("Skipping " + Pair + " Queue Task because already exists", "TICKPROCESSING", LOGLEVEL.DEBUG);
}
}
I am not really sure why I am getting OOM, but it looks similar to: http://blogs.microsoft.co.il/bnaya/2012/02/26/real-life-story-blocking-collection/ But I am not using parallel here... My Queues are empty though since week end market is closed. Would using another timer with TryDequeue a better approach ? Any advice would be welcome !