关于垃圾收集的问题C#.NET

时间:2010-08-07 08:35:53

标签: c# garbage-collection

我在使用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();

这里有什么能阻止以前的文本挖掘算法对象被垃圾收集吗?

5 个答案:

答案 0 :(得分:4)

我建议首先确定究竟是什么泄漏。 然后假设一个原因(例如事件处理程序中的引用)。

确定泄漏的内容:

  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用于32位.NET 2.0-3.5

    .load C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\sos.dll用于32位.NET 4.0

    .load C:\WINDOWS\Microsoft.NET\Framework64\v2.0.50727\sos.dll用于64位.NET 2.0-3.5

    .load C:\WINDOWS\Microsoft.NET\Framework64\v4.0.30319\sos.dll用于64位.NET 4.0

  5. 您现在可以在立即窗口中运行SoS命令。我建议检查!dumpheap -stat的输出,如果没有查明问题,请检查!finalizequeue

  6. 注意:

    • 启用本机调试后第一次运行程序可能需要很长时间(分钟),如果你已设置VS加载符号。
    • 我建议的调试器命令都以!(感叹号)开头。

    这些说明是由微软令人难以置信的TessAdvanced .NET Debugging的作者Mario Hewardt提供的。

    根据 对象泄漏的情况确定泄漏后,然后假设原因并实施修复。然后,您可以再次执行这些步骤以确定修复是否有效。

答案 1 :(得分:3)

1)正如我在评论中所说,如果您在代码中使用事件(AddAlgorithmListeners让我怀疑这一点),订阅某个事件可以创建一个“隐藏的“容易被遗忘的对象之间的依赖关系。这种依赖关系可能意味着一个对象没有被释放,因为有人仍在监听它的一个事件。当您不再需要收听时,请确保取消订阅所有活动。


2)此外,我想指出您的代码中的一个(可能不是那么偏离主题)问题:

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

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

调用此方法时是否已初始化algoritm?否则,设置algorithm.LexiconEntries似乎不是一件有效的事情。这意味着你的方法依赖于某种外部状态,对我而言,这似乎是程序逻辑中存在bug的潜在地方。

如果我理解正确,该对象包含描述算法的一些状态,CreateNewAlgorithmObject从当前状态导出algorithm的新状态。如果这是我的代码,我将algorithm作为所有函数的显式参数,作为该方法依赖于此对象的信号。它将不再被隐藏为“外部”你的职能所依赖的国家。

PS:如果您不想沿着这条路走下去,那么您可以考虑使代码更加一致的另一件事就是将CreateNewAlgorithmObject转换为void方法 - 直接在该方法中分配algorithm

答案 2 :(得分:1)

AddAlgorithmListeners是否将事件处理程序附加到算法对象公开的事件?听取对象的生存时间是否长于算法对象 - 在这种情况下,它们可以继续保持算法对象的收集。

如果是,请在让对象超出范围之前尝试取消订阅事件。

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

答案 3 :(得分:0)

我的嫌疑人在AddAlgorithmListeners();你确定在执行完毕后删除了监听器吗?

答案 4 :(得分:0)

IEnumerable返回的GetGroup()是丢弃还是缓存?也就是说,它是否会保留它所发射的对象,就好像它一样,它会在每次迭代时呈线性增长。

内存分析很有用,您是否尝试使用分析器检查应用程序?我发现Red Gate过去很有用(它不是免费的,但确实有评估版,IIRC)。