我在使用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();
这里有什么能阻止以前的文本挖掘算法对象被垃圾收集吗?
答案 0 :(得分:4)
我建议首先确定究竟是什么泄漏。 然后假设一个原因(例如事件处理程序中的引用)。
确定泄漏的内容:
Properties -> Debug ->
检查Enable unmanaged code debugging
。Debug -> Break All
。Debug -> Windows -> Immediate
在即时窗口中输入以下内容之一,具体取决于您运行的是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
您现在可以在立即窗口中运行SoS命令。我建议检查!dumpheap -stat
的输出,如果没有查明问题,请检查!finalizequeue
。
注意:
!
(感叹号)开头。这些说明是由微软令人难以置信的Tess和Advanced .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)。