簡體   English   中英

關於垃圾收集的問題C#.NET

[英]Question about Garbage collection C# .NET

我在使用OutOfMemoryException的應用程序中遇到問題。 我的應用程序可以搜索文本中的單詞。 當我開始一個長時間運行的進程搜索大約2175個不同的單詞搜索大約2000個不同的文本時,應用程序將通過OutOfMemoryException(大約6個小時的處理后)終止大約50%

我一直試圖找到內存泄漏。 我有一個像這樣的對象圖:( - >是引用)

靜態全局應用程序對象(控制器) - >算法啟動器對象 - >文本挖掘啟動器對象 - >文本挖掘算法對象(此對象執行搜索)。

文本挖掘入門對象將在單獨的線程中啟動文本挖掘算法對象的run() - 方法。

為了解決這個問題,我編寫了代碼,以便文本挖掘入門對象將文本拆分為多個組並按順序為每組文本初始化一個文本挖掘算法對象(因此當一個文本挖掘算法對象完成時)將創建一個新的搜索下一組文本)。 在這里,我將以前的文本挖掘算法對象設置為null。 但這並沒有解決問題。

當我創建一個新的文本挖掘算法對象時,我必須給它一些參數。 在將該對象設置為null之前,這些屬性取自先前文本挖掘算法對象的屬性。 這會阻止文本挖掘算法對象的垃圾收集嗎?

以下是文本挖掘算法啟動程序創建新文本挖掘算法對象的代碼:

    private void RunSeveralAlgorithmObjects()
    {

        IEnumerable<ILexiconEntry> currentEntries = allLexiconEntries.GetGroup(intCurrentAlgorithmObject, intNumberOfAlgorithmObjectsToUse);

        algorithm.LexiconEntries = currentEntries;
        algorithm.Run();

        intCurrentAlgorithmObject++;

        for (int i = 0; i < intNumberOfAlgorithmObjectsToUse - 1; i++)
        {
            algorithm = CreateNewAlgorithmObject();
            AddAlgorithmListeners();
            algorithm.Run();
            intCurrentAlgorithmObject++;
        }

    }

    private TextMiningAlgorithm CreateNewAlgorithmObject()
    {
        TextMiningAlgorithm newAlg = new TextMiningAlgorithm();

        newAlg.SortedTermStruct = algorithm.SortedTermStruct;
        newAlg.PreprocessedSynonyms = algorithm.PreprocessedSynonyms;
        newAlg.DistanceMeasure = algorithm.DistanceMeasure;
        newAlg.HitComparerMethod = algorithm.HitComparerMethod;
        newAlg.LexiconEntries = allLexiconEntries.GetGroup(intCurrentAlgorithmObject, intNumberOfAlgorithmObjectsToUse);
        newAlg.MaxTermPercentageDeviation = algorithm.MaxTermPercentageDeviation;
        newAlg.MaxWordPercentageDeviation = algorithm.MaxWordPercentageDeviation;
        newAlg.MinWordsPercentageHit = algorithm.MinWordsPercentageHit;
        newAlg.NumberOfThreads = algorithm.NumberOfThreads;
        newAlg.PermutationType = algorithm.PermutationType;
        newAlg.RemoveStopWords = algorithm.RemoveStopWords;
        newAlg.RestrictPartialTextMatches = algorithm.RestrictPartialTextMatches;
        newAlg.Soundex = algorithm.Soundex;
        newAlg.Stemming = algorithm.Stemming;
        newAlg.StopWords = algorithm.StopWords;
        newAlg.Synonyms = algorithm.Synonyms;
        newAlg.Terms = algorithm.Terms;
        newAlg.UseSynonyms = algorithm.UseSynonyms;

        algorithm = null;

        return newAlg;
    }

以下是運行整個搜索過程的線程的開始:

            // Run the algorithm in it's own thread
            Thread algorithmThread = new Thread(new ThreadStart
                (RunSeveralAlgorithmObjects));
            algorithmThread.Start();

這里有什么東西可以防止以前的文本挖掘算法對象被垃圾收集?

我建議首先確定究竟是什么泄漏。 然后假設一個原因(例如事件處理程序中的引用)。

確定泄漏的內容:

  1. 為項目啟用本機調試。 Properties -> Debug ->檢查Enable unmanaged code debugging
  2. 運行程序。 由於內存泄漏可能是漸進的,你可能不需要讓它運行整整6個小時; 讓它運行一段時間然后Debug -> Break All
  3. 打開立即窗口。 Debug -> Windows -> Immediate
  4. 在即時窗口中鍵入以下內容之一,具體取決於您運行的是32位還是64位,.NET 2.0 / 3.0 / 3.5還是.NET 4.0:

    .load C:\\WINDOWS\\Microsoft.NET\\Framework\\v2.0.50727\\sos.dll for 32-bit .NET 2.0-3.5

    .load C:\\WINDOWS\\Microsoft.NET\\Framework\\v4.0.30319\\sos.dll for 32-bit .NET 4.0

    .load C:\\WINDOWS\\Microsoft.NET\\Framework64\\v2.0.50727\\sos.dll for 64-bit .NET 2.0-3.5

    .load C:\\WINDOWS\\Microsoft.NET\\Framework64\\v4.0.30319\\sos.dll for 64-bit .NET 4.0

  5. 您現在可以在立即窗口中運行SoS命令。 我建議檢查!dumpheap -stat的輸出,如果沒有查明問題,請檢查!finalizequeue

筆記:

  • 如果您已將VS設置為加載符號,則在啟用本機調試后第一次運行該程序可能需要很長時間(分鍾)。
  • 我推薦的調試器命令都是從! (感嘆號)。

這些說明是由微軟的Tess高級.NET調試的作者Mario Hewardt提供的。

一旦根據哪個對象泄漏確定了泄漏, 然后假定原因並實施修復。 然后,您可以再次執行這些步驟以確定該修復是否有效。

1)正如我在評論中所說,如果您在代碼中使用事件( AddAlgorithmListeners讓我懷疑這一點), 訂閱事件可以在對象之間創建一個容易被遺忘的“隱藏”依賴關系。 這種依賴關系可能意味着一個對象沒有被釋放,因為有人仍然在監聽它的一個事件。 確保在不再需要收聽時取消訂閱所有活動。


2)另外,我想指出你的代碼中的一個(可能不是那么偏離主題)問題:

private void RunSeveralAlgorithmObjects()
{
    ...
    algorithm.LexiconEntries = currentEntries;
    // ^ when/where is algorithm initialized?

    for (...)
    {
        algorithm = CreateNewAlgorithmObject();
        ....
    }
}

algoritm在調用此方法時是否已初始化algoritm 否則,設置algorithm.LexiconEntries似乎不是一件有效的事情。 這意味着你的方法依賴於某些外部狀態,對我來說這看起來像是程序邏輯中存在錯誤的潛在位置。

如果我理解正確,該對象包含描述算法的一些狀態, CreateNewAlgorithmObject從當前狀態派生algorithm的新狀態。 如果這是我的代碼, 我會將algorithm作為所有函數的顯式參數,作為該方法依賴於此對象的信號。 然后,它將不再隱藏在您的函數所依賴的“外部”狀態。

PS:如果你不想沿着那條路走下去,你可以考慮使你的代碼更加一致的另一件事是將CreateNewAlgorithmObject變成一個void方法並直接在該方法中重新分配algorithm

AddAlgorithmListeners是否將事件處理程序附加到算法對象公開的事件? 聽取對象是否比算法對象更長 - 在這種情況下,它們可以繼續保持算法對象不被收集。

如果是,請在讓對象超出范圍之前嘗試取消訂閱事件。

for (int i = 0; i < intNumberOfAlgorithmObjectsToUse - 1; i++)
        {
            algorithm = CreateNewAlgorithmObject();
            AddAlgorithmListeners();
            algorithm.Run();
            RemoveAlgoritmListeners();    // See if this fixes your issue.
            intCurrentAlgorithmObject++;
        }

我懷疑是在AddAlgorithmListeners(); 你確定在執行完成后刪除了監聽器嗎?

GetGroup()返回的IEnumerable是丟棄還是緩存? 也就是說,它是否保持它所發射的對象,就好像它一樣,它顯然會隨着每次迭代而線性增長。

內存分析很有用,您是否嘗試使用分析器檢查應用程序? 我發現Red Gate過去很有用(它不是免費的,但確實有評估版,IIRC)。

暫無
暫無

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

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