2016-05-01 133 views
0

我正在编写一个外汇交易机器人,并且在使用BlockingCollection一段时间后(约2小时)运行outOfMemory异常。 我基本1个队列对贸易图表,被加入到一个字典:c#BlockingCollection导致内存不足

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

最后,我的任务,检查问:

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一起使用另一个计时器会有更好的方法吗? 任何建议将受到欢迎!

+0

它看起来像你正在使用System.Timers.Timer?如果是这样,那么间隔是多少?计时器标记方法需要多长时间?定时器上AutoReset的值是多少? –

+0

我没有看到明显的问题,但我没有听说您发布的链接问题。但是...如果它是相似的,尝试使用TaskFactory.StartNew启动任务,并将TaskCreationOptions设置为LongRunning 另外:1)您的命名约定很糟糕,您无法看到与类,局部变量,方法不同的...尝试将其更改为更多的C#,如:P 2)摆脱ToUpper()通过设置额外的构造函数参数给StringComparer.InvariantCultureIgnoreCase :)它将更干净,更快 – Carnifex

+0

嘿,我有计时器每隔50ms启动.. 。我实际上认为我的问题可能是由于计时器事件堆积而造成的......我会尝试手动重置并让您知道。仅供参考,定时器定义: TickTimer = new System.Timers.Timer(); TickTimer.Elapsed + = new ElapsedEventHandler(TickTimer_tick); TickTimer.Interval = GlobalSettings.APISleepDelayMSTick; // 50 MS TickTimer.AutoReset = true; //让计时器触发重复事件(true为默认值) TickTimer.Enabled = true; – bmigette

回答

0

我切换定时器来手动像这样:

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

     } 

,它似乎已经解决了我的问题。 我也确保在Q中发送滴答,并且它们由Receiver重复过滤,这样排队线程永远不会挂起太久。 感谢您的指针!