c#BlockingCollection导致内存不足

时间:2016-05-01 07:45:54

标签: c# out-of-memory blockingcollection

我正在编写外汇交易机器人,我使用BlockingCollection在一段时间(大约2小时)后运行outOfMemory异常。 我基本上有一个队列对交易图表,它被添加到一个字典中:

        private Dictionary<string, BlockingCollection<tick>> tickQueues = new Dictionary<string, BlockingCollection<tick>>();

我在一小时后检查内存转储,我可以看到以下项目堆积起来:

                                     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

我有一个负责将数据添加到队列的计时器:

   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);
            }
        }

最后,我的任务是检查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);
            }
        }

我不确定为什么我会收到OOM,但它看起来类似于: http://blogs.microsoft.co.il/bnaya/2012/02/26/real-life-story-blocking-collection/ 但我不是在这里使用并行...虽然周末市场已关闭,但我的队列是空的。 使用TryDequeue的另一个计时器会更好吗? 欢迎任何建议!

1 个答案:

答案 0 :(得分:0)

我将计时器切换为手动,如下所示:

private void TickTimer_tick(object source, ElapsedEventArgs e) {
           try {
            //...
            } finally {
                TickTimer.Start();
            }

        }

它似乎解决了我的问题。 我也确保在Q中发送tick,并且它们由Receiver重复过滤,因此Queing线程永远不会等待太长时间。 谢谢你的指针!