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一起使用另一個計時器會有更好的方法嗎? 任何建議將受到歡迎!
它看起來像你正在使用System.Timers.Timer?如果是這樣,那麼間隔是多少?計時器標記方法需要多長時間?定時器上AutoReset的值是多少? –
我沒有看到明顯的問題,但我沒有聽說您發佈的鏈接問題。但是...如果它是相似的,嘗試使用TaskFactory.StartNew啓動任務,並將TaskCreationOptions設置爲LongRunning 另外:1)您的命名約定很糟糕,您無法看到與類,局部變量,方法不同的...嘗試將其更改爲更多的C#,如:P 2)擺脫ToUpper()通過設置額外的構造函數參數給StringComparer.InvariantCultureIgnoreCase :)它將更乾淨,更快 – Carnifex
嘿,我有計時器每隔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