关于c#:进程内存大小-不同的计数器

关于c#:进程内存大小-不同的计数器

Process Memory Size - Different Counters

我正试图找出自己的.Net服务器进程正在使用多少内存(用于监视和记录目的)。

我正在使用:

1
Process.GetCurrentProcess().PrivateMemorySize64

但是,Process对象具有几个不同的属性,这些属性使我可以读取所使用的内存空间:
分页,非分页,PagedSystem,NonPagedSystem,私有,虚拟,WorkingSet

然后是" peaks ":我想它只是存储这些最后一次使用的最大值。

通读每个属性的MSDN定义对我来说并没有太大帮助。我不得不承认我对内存管理方式的知识(就分页和虚拟而言)非常有限。

所以我的问题显然是"我应该使用哪个?",我知道答案是"取决于情况"。

此过程基本上将一堆列表保存在正在发生的事情中,而其他进程则与之通信并查询其内容。我期望运行该服务器的服务器需要大量RAM,因此,随着时间的推移,我要查询此数据,以便与保留在其中的列表大小相比能够估计RAM需求。 >

那么...我应该使用哪一个?为什么?


如果您想知道GC使用了多少,请尝试:

1
GC.GetTotalMemory(true)

如果您想从Windows中了解您的进程使用什么(TaskManager中的" VM Size"列),请尝试:

1
Process.GetCurrentProcess().PrivateMemorySize64

如果您想知道进程在RAM中的内容(而不是在页面文件中)(TaskManager中的"内存使用情况"列),请尝试:

1
Process.GetCurrentProcess().WorkingSet64

有关不同种类的内存的更多说明,请参见此处。


好的,我在Google上找到了拉斯提到的页面,我相信这对于那些不太了解内存工作原理的人(例如我)来说是一个很好的解释。

http://shsc.info/WindowsMemoryManagement

我的简短结论是:

  • 私有字节=我的进程请求存储数据的内存。其中一些可能已分页到磁盘,也可能未分页到磁盘。这是我一直在寻找的信息。

  • 虚拟字节=专用字节,再加上与其他进程共享的已加载DLL等的空间。

  • 工作集=我的进程的所有内存中尚未分页到磁盘的部分。因此,分页到磁盘的数量应为(虚拟-工作集)。

感谢您的帮助!


如果要使用Windows Vista任务管理器中所示的"内存(专用工作集)"(相当于进程资源管理器" WS专用字节"),请使用以下代码。最好将这个无限循环扔到线程/后台任务中以获取实时统计信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using System.Threading;
using System.Diagnostics;

//namespace...class...method

Process thisProc = Process.GetCurrentProcess();
PerformanceCounter PC = new PerformanceCounter();

PC.CategoryName ="Process";
PC.CounterName ="Working Set - Private";
PC.InstanceName = thisProc.ProcessName;

while (true)
{
 String privMemory = (PC.NextValue()/1000).ToString()+"KB (Private Bytes)";
 //Do something with string privMemory

 Thread.Sleep(1000);
}


要获得任务管理器所赋予的价值,我要对上面的Mike Regan的解决方案表示敬意。但是,有一个变化:它不是:perfCounter.NextValue()/1000;而是perfCounter.NextValue()/1024;(即实际千字节)。这将提供您在任务管理器中看到的确切值。

以下是一个完整的解决方案,用于在WPF或WinForms应用程序中简单显示"内存使用情况"(任务管理器,如给定)(在这种情况下,仅在标题中)。只需在新的Window构造函数中调用此方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    private void DisplayMemoryUsageInTitleAsync()
    {
        origWindowTitle = this.Title; // set WinForms or WPF Window Title to field
        BackgroundWorker wrkr = new BackgroundWorker();
        wrkr.WorkerReportsProgress = true;

        wrkr.DoWork += (object sender, DoWorkEventArgs e) => {
            Process currProcess = Process.GetCurrentProcess();
            PerformanceCounter perfCntr = new PerformanceCounter();
            perfCntr.CategoryName ="Process";
            perfCntr.CounterName ="Working Set - Private";
            perfCntr.InstanceName = currProcess.ProcessName;

            while (true)
            {
                int value = (int)perfCntr.NextValue() / 1024;
                string privateMemoryStr = value.ToString("n0") +"KB [Private Bytes]";
                wrkr.ReportProgress(0, privateMemoryStr);
                Thread.Sleep(1000);
            }
        };

        wrkr.ProgressChanged += (object sender, ProgressChangedEventArgs e) => {
            string val = e.UserState as string;
            if (!string.IsNullOrEmpty(val))
                this.Title = string.Format(@"{0}   ({1})", origWindowTitle, val);
        };

        wrkr.RunWorkerAsync();
    }`

这是一个公平的描述吗?我想与我的团队分享此信息,所以请让我知道它是否不正确(或不完整):

C#中有几种方法可以询问我的进程正在使用多少内存。

  • 可以(通过CLR)管理已分配的内存,也可以不进行管理。
  • 分配的内存可以是虚拟的(存储在磁盘上),也可以是已加载的(进入RAM页面)
  • 分配的内存可以是私有的(仅由进程使用)或共享的(例如,属于其他进程正在引用的DLL)。

鉴于以上所述,以下是一些在C#中测量内存使用情况的方法:

1)Process.VirtualMemorySize64():返回进程使用的所有内存-托管或非托管,虚拟或加载,私有或共享。

2)Process.PrivateMemorySize64():返回进程使用的所有私有内存-托管或非托管,虚拟或已加载。

3)Process.WorkingSet64():返回进程使用的所有私有,已加载内存-托管或非托管

4)GC.GetTotalMemory():返回垃圾回收器正在监视的托管内存量。


我建议还监视页面错误的发生频率。当您尝试访问一些已从物理内存移动到交换文件的数据,并且系统必须从磁盘读取页面之前,才可以访问此数据。


工作集不是一个很好的属性。根据我的收集,它包括该进程可以触及的所有内容,甚至包括多个进程共享的库,因此您会在该计数器中看到重复计数的字节。私有内存是一个更好看的计数器。


推荐阅读