2016-05-01 135 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重複過濾,這樣排隊線程永遠不會掛起太久。 感謝您的指針!