簡體   English   中英

為什么GC System.Threading.OverlappedData需要這么長時間?

[英]Why is it taking so long to GC System.Threading.OverlappedData?

我正在通過內存分析器運行我的應用程序來檢查泄漏。 事情似乎有點好,但我得到了很多這些OverlappedData似乎在終結器隊列中徘徊,幾乎沒有任何東西。 它們是通過關閉連接任一端的底層NetworkStream而取消的重疊IO的結果。

網絡流本身被丟棄。 任何地方都沒有NetworkStream實時實例。

通常它們的根源是被稱為OverlappedDataCacheLine的東西。我在回調中調用EndRead是我做的第一件事,因此沒有調用BeginRead應該沒有它的相應EndRead

這是一個非常典型的外觀,是誰從工具中保留它

OverlappedData正在幫助

最后它確實得到了GC但它需要永遠 - 大約半小時的時間來殺死所有內容,當我開始大約一千個流時,將它們放入異步調用BeginRead並在大約一分鍾后關閉它們。

該程序在端口80上對網絡服務器稍微重現了這個問題。任何網絡服務器都會真正做到。

using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Threading;

class Program
{
    static void Main(string[] args)
    {
        var clients = new List<TcpClient>();
        for (int i = 0; i < 1000; ++i) {
            var client = new TcpClient();
            clients.Add(client);

            client.BeginConnect("localhost", 80, connectResult =>
                {
                    client.EndConnect(connectResult);

                    var stream = client.GetStream();
                    stream.BeginRead(new byte[1000], 0, 1000, result =>
                        {
                            try
                            {
                                stream.EndRead(result);
                                Console.WriteLine("Finished (should not happen)");
                            }
                            catch
                            {
                                // Expect to find an IO exception here
                                Console.WriteLine("Faulted");                               
                            }
                        }, stream);     
                }, client);             
        }

        Thread.Sleep(10000); // Make sure everything has time to connect

        foreach (var tcpClient in clients)
        {
            tcpClient.GetStream().Close();
            tcpClient.Close();
        }
        clients.Clear(); // Make sure the entire list can be GC'd

        Thread.Sleep(Timeout.Infinite); // Wait forever. See in profiler to see the overlapped IO take forever to go away
    }
}

當然,這個程序並不需要永遠清理OverlappedData一千個OverlappedData因為它比真正的應用程序要小,但確實需要一段時間來完成它。 在運行真實的東西而不是這個測試應用程序時,我會收到卡住終結器的警告。 它在我的應用程序中沒有做太多,只是嘗試關閉可能沒有關閉的所有內容,並確保沒有任何引用被保存在任何地方。

如果我在客戶端上調用Dispose()Close()並且它是流,那么它似乎並不重要。 結果是一樣的。

任何線索,為什么會發生這種情況以及如何避免這種情況? CLR對我來說很聰明,並且保留這​​些固定的內存塊可能會為新的呼叫做准備嗎? 為什么終結者的完成速度如此之慢?

更新在做了一些令人難以置信的愚蠢的負載測試之后,在F5鍵上放一杯水並喝點咖啡,似乎有些東西會在收集這些東西的壓力下觸發更完整的GC。 所以實際上似乎並不是一個真正的問題,但仍然很高興知道這里實際發生了什么,為什么收集這個對象的速度比其他對象慢,如果這可能是一個問題,在后期階段與碎片記憶等。

好吧,現在看來發生了什么。 只有在分配內存時才會發生垃圾收集。 它需要至少2兆字節的分配,即生成0 GC堆的典型初始大小以觸發GC。 換句話說,一個什么都不做的程序永遠不會運行GC,你會看到任何尚未在堆中使用內存分析器收集的對象很長一段時間。

這是對你描述的內容的一個很好的解釋。 終止所有連接后,您的程序不再需要執行任何操作。 因此,如果任何內存不會分配太多,所以不會觸發集合。 如果您的探查器沒有顯示集合,那么您可以使用Perfmon.exe查看它們。 這根本不是問題,只是垃圾收集器如何工作的副作用。

只有在有明確證據表明程序存在失控的資源消耗問題時,才會擔心泄漏。

嘗試從AsyncResult獲取客戶端以排除任何lambda閉包問題。

TcpClient t = (TcpClient)connectResult.AsyncState;

另外,您不應該完成處理調用EndConnect嗎?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM