我一直在使用methodology outlined by Shivprasad Koirala来检查C#应用程序(VoiceAttack)中运行的代码是否存在内存泄漏。基本上,它涉及使用性能监视器来跟踪应用程序的专用字节以及所有堆中的字节,并比较这些计数器以评估是否存在泄漏以及泄漏的类型(托管/非托管)。理想情况下,我需要在Visual Studio之外进行测试,这就是为什么我使用此方法的原因。
下面的代码部分将生成以下内存配置文件(请记住,与Visual Studio相比,该代码的格式略有不同,因为这是主C#应用程序中包含的功能):
public void main()
{
string FilePath = null;
using (FileDialog myFileDialog = new OpenFileDialog())
{
myFileDialog.Title = "this is the title";
myFileDialog.FileName = "testFile.txt";
myFileDialog.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
myFileDialog.FilterIndex = 1;
if (myFileDialog.ShowDialog() == DialogResult.OK)
{
FilePath = myFileDialog.FileName;
var extension = Path.GetExtension(FilePath);
var compareType = StringComparison.InvariantCultureIgnoreCase;
if (extension.Equals(".txt", compareType) == false)
{
FilePath = null;
VA.WriteToLog("Selected file is not a text file. Action canceled.");
}
else
VA.WriteToLog(FilePath);
}
else
VA.WriteToLog("No file selected. Action canceled.");
}
VA.WriteToLog("done");
}
您可以看到,运行此代码后,专用字节不会返回原始计数,并且所有堆中的字节都大致恒定,这意味着一部分非托管内存尚未释放。连续运行此相同的内联函数几次不会导致进一步增加到观察到的最大专用字节或未释放的内存。一旦主C#应用程序(VoiceAttack)关闭,所有相关的内存(包括上述代码的内存)将被释放。坏消息是,在正常情况下,主应用程序可能会被用户无限期地运行,从而导致分配的内存保持未释放状态。
为了很好的衡量,我将相同的代码放入了VS(在Thread.Sleep(5000)
块之前和之后添加了一对using
,以进行更好的图形分析),并构建了一个可执行文件以使用Performance Monitor方法进行跟踪,结果是一样的。 OpenFileDialog会有一个初始的非托管内存跳转,并且分配的非托管内存永远不会恢复到原始值。
上面概述的内存和泄漏跟踪方法是否有意义?如果是,是否可以采取任何措施来正确释放非托管内存?
答案 0 :(得分:2)
上面概述的内存和泄漏跟踪方法是否有意义?
不。您不应该期望总是释放非托管的承诺内存(专用字节)。例如,进程具有非托管堆,该堆被管理以允许后续分配。而且,由于Windows可以分页已提交的内存,因此最小化每个进程的已提交内存并不重要。
答案 1 :(得分:1)
如果重复调用没有增加内存使用量,则说明没有内存泄漏,因此延迟了初始化。在使用某些组件之前,它们不会被初始化,因此在建立基线时不会考虑它们的内存使用情况。