2012-05-21 11 views
8

在我的某些異步tcp服務器代碼中,偶爾會發生錯誤,導致進程消耗整個系統的內存。在查看日誌,事件查看器和一些MS docs時,如果「調用應用程序多次對同一客戶端進行異步IO調用,那麼如果遠程客戶端停止I/O的結尾,您可能會看到堆碎片和私人字節增加, O「,這會導致System.Threading.OverlappedData結構和字節數組在內存使用率和釘扎方面出現尖峯。如何停止異步tcp .NET代碼使用整個系統的資源

知識庫文章建議的解決方案是「用異步IO設置未完成緩衝區(發送或接收)數量的上限」。

這是怎麼回事?這是指發送到BeginRead的字節[]嗎?那麼解決方案是簡單地用信號包裝訪問byte []的嗎?

編輯:信號量控制訪問字節緩衝區或只是有靜態大小的字節緩衝池是兩種常見的解決方案。我仍然存在的一個問題是,當這個異步客戶端問題發生(可能實際上是一些奇怪的網絡事件)時,使用信號量或字節緩衝池將會阻止我耗盡內存,但它不能解決問題。我的緩衝池可能會被問題客戶端吞併,實際上鎖定了正確的功能合法客戶端。編輯2:遇到這個偉大的answer。基本上它顯示瞭如何手動取消固定對象。儘管異步TCP代碼留在了幕後運行時規則中,但可能會在使用之前明確固定每個緩衝區,然後在塊末尾或終點處取消固定,從而覆蓋該代碼。我試圖找出現在...

+0

可能的重複:http://stackoverflow.com/questions/236171/net-does-not-have-reliable-asynchronouos-socket-communication – Dennis

+0

這是關於使用信號封裝調用BeginRead。 – mikalai

+0

也許這是一個很好的理由來剖析代碼... – gsscoder

回答

3

解決該問題的一種方法是預先分配緩衝區和異步通信中使用的其他數據結構。如果您在啓動時進行預分配,則不會出現碎片,因爲內存自然會駐留在堆的同一區域中。

我建議使用ReceiveAsync/SendAsync的API添加到.NET 3.5 SP1,它允許你緩存或預分配兩個SocketAsyncEventArgs結構和存儲在SocketAsyncEventArgs.Buffer財產內存緩衝區,不像老BeginXXX/EndXXX的API只允許緩存或預分配內存緩衝區。

使用舊的API也會導致巨大的CPU成本,因爲API內部一次又一次地創建了Windows重疊I/O結構。在新的API中,這發生在SocketAsyncEventArgs之內,所以通過彙集這些對象,CPU成本只支付一次。

關於固定的更新:鎖定是有原因的,即防止GC在碎片整理期間移動緩衝區。通過手動解鎖,可能會導致內存損壞。