【问题标题】:How to calculate private working set (memory)?如何计算私有工作集(内存)?
【发布时间】:2011-02-06 08:33:47
【问题描述】:

如何使用 C# 计算私有工作内存集?我有兴趣生成与taskmgr.exe 大致相同的数字。

我正在使用 Process 命名空间并使用 WorkingSet64PrivateMemorySize64 等方法/数据,但这些数字有时会相差 100MB 或更多。

【问题讨论】:

    标签: c# memory memory-management


    【解决方案1】:

    这是一个高度可变的数字,你无法计算它。 Windows 内存管理器不断将​​页面换入和换出 RAM。 TaskMgr.exe 从性能计数器中获取它。你可以像这样得到相同的数字:

    using System;
    using System.Diagnostics;
    
    class Program {
        static void Main(string[] args) {
            string prcName = Process.GetCurrentProcess().ProcessName;
            var counter = new PerformanceCounter("Process", "Working Set - Private", prcName);
            Console.WriteLine("{0}K", counter.RawValue / 1024);
            Console.ReadLine();
        }
    }
    

    请注意,这个数字实际上并没有多大意义,当其他进程启动并竞争 RAM 时,它会下降。

    【讨论】:

    • 你是什么意思,“这个数字真的没有多大意义”?这个数字不是代表进程使用了​​多少内存而不能与另一个进程共享吗?我有兴趣构建一个将杀死进程“滥用”进程的服务 - “滥用”被定义为使用超过 x 多 MB 内存的进程。如果我使用的数字真的没有多大意义,我会讨厌编写服务。你有什么建议?
    • 不,这不是这个数字的意思。您正在寻找“Private Bytes”,即一个进程占用的、其他进程无法共享的虚拟内存量。
    • 虽然说的都是正确的,但我想补充一点,仅使用ProcessName 查找匹配的计数器实例是不够的。如果您有多个相同的进程(例如 svchost.exe),那么计数器名称将是“svchost#1”、“svchost#2”等。您需要通过“ID 进程”计数器进行匹配,这也是一部分进程类别,Process.ID.
    【解决方案2】:

    对于未来的用户,这是我必须做的,以确保为可能有多个实例的进程获取私有工作集。我调用CurrentMemoryUsage,它从GetNameToUseForMemory 获取适当的进程名称。我发现这个循环很慢,即使我可以过滤掉结果。所以,这就是为什么您会看到 GetNameToUseForMemory 使用字典来缓存名称。

    private static long CurrentMemoryUsage(Process proc)
    {
      long currentMemoryUsage;
      var nameToUseForMemory = GetNameToUseForMemory(proc);
      using (var procPerfCounter = new PerformanceCounter("Process", "Working Set - Private", nameToUseForMemory))
      {
        //KB is standard
        currentMemoryUsage = procPerfCounter.RawValue/1024;
      }
      return currentMemoryUsage;
    }
    
    private static string GetNameToUseForMemory(Process proc)
    {
      if (processId2MemoryProcessName.ContainsKey(proc.Id))
        return processId2MemoryProcessName[proc.Id];
      var nameToUseForMemory = String.Empty;
      var category = new PerformanceCounterCategory("Process");
      var instanceNames = category.GetInstanceNames().Where(x => x.Contains(proc.ProcessName));
      foreach (var instanceName in instanceNames)
      {
        using (var performanceCounter = new PerformanceCounter("Process", "ID Process", instanceName, true))
        {
          if (performanceCounter.RawValue != proc.Id) 
            continue;
          nameToUseForMemory = instanceName;
          break;
        }
      }
      if(!processId2MemoryProcessName.ContainsKey(proc.Id))
        processId2MemoryProcessName.Add(proc.Id, nameToUseForMemory);
      return nameToUseForMemory;
    }
    

    【讨论】:

    猜你喜欢
    • 2014-09-13
    • 1970-01-01
    • 2011-04-15
    • 1970-01-01
    • 2023-04-09
    • 1970-01-01
    • 2016-12-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多