1

我一直在使用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以便更好地进行图形分析)并构建了一个可执行文件以使用性能监视器方法进行跟踪,结果是相同的。OpenFileDialog 有一个初始的非托管内存跳转,分配的非托管内存永远不会回到原始值。

上面概述的内存和泄漏跟踪方法是否有意义?如果是,是否可以采取任何措施来正确释放非托管内存?

4

2 回答 2

2

上面概述的内存和泄漏跟踪方法是否有意义?

不,你不应该期望非托管的提交内存(私有字节)总是被释放。例如进程有一个非托管堆,它被管理以允许后续分配。由于 Windows 可以分页您提交的内存,因此最小化每个进程提交的内存并不重要。

于 2018-12-14T18:06:41.123 回答
1

如果重复调用没有增加内存使用,则说明没有内存泄漏,说明延迟了初始化。某些组件在您使用它们之前不会被初始化,因此在您建立基线时不会考虑它们的内存使用情况。

于 2018-12-14T18:07:57.233 回答