【问题标题】:Optimal way to get Private Working Set Memory in C# for a specific instance of a process在 C# 中为特定进程实例获取私有工作集内存的最佳方法
【发布时间】:2019-05-01 22:42:09
【问题描述】:

我正在构建一个小型控制台应用程序,该应用程序会强制关闭使用一定内存量的进程,并且当 CPU 已经在使用其大量功率时,我正在努力让它正常工作。

每当我使用 PerformanceCounter 获取 Private Working Set 内存时,我很容易陷入以下异常:

发生了一个或多个错误

在我看来,如果我将 PerformanceCounter “附加”到一个进程,我就不能再简单地 .Kill() 它了。这当然是一个较慢的过程,即使是获取值也是如此。

当我使用任务管理器时,我可以清楚地看到一个进程的内存使用情况。如果我进入 Details 选项卡,我可以看到 memory 列实际上是“Private Working Set”值。

有没有办法以更优化、更快的方式获得此值?

这是我用来通过 PerformanceCounter 获取私有工作集的代码:

public static long GetPrivateWorkingSetMemoryOfProcess(Process process)
{
    long process_size = 0;
    String InstanceName = PerformanceCounterInstanceName(process);
    var counter = new PerformanceCounter("Process", "Working Set - Private", InstanceName, true);
    process_size = Convert.ToInt32(counter.NextValue()) / 1024;
    return process_size;
}

由于 PerformanceCounter 使用进程名称作为参数,而不是 ID,因此我使用此函数来获取进程的正确进程名称:

public static string PerformanceCounterInstanceName(this Process process)
{
    var matchesProcessId = new Func<string, bool>(instanceName =>
    {
        using (var pc = new PerformanceCounter("Process", "ID Process", instanceName, true))
        {
            if ((int)pc.RawValue == process.Id)
            {
                return true;
            }
        }
        return false;
    });

    string processName = Path.GetFileNameWithoutExtension(process.ProcessName);
    return new PerformanceCounterCategory("Process")
           .GetInstanceNames()
           .AsParallel()
           .FirstOrDefault(instanceName => instanceName.StartsWith(processName)
                                           && matchesProcessId(instanceName));
}

这里是我将使用它来杀死具有一定内存使用量的进程的地方:

//get Process By ID
Process processToClose = Process.GetProcessById(Convert.ToInt32(processid));

long processesPrivateWorkingSetMemoryUsage = GetPrivateWorkingSetMemoryOfProcess(processToClose);
Console.WriteLine("Process '" + processid + "' uses " + processesPrivateWorkingSetMemoryUsage.ToString() + " memory.");
if (processesPrivateWorkingSetMemoryUsage <= 8000)
{
    processToClose.Kill()
}

【问题讨论】:

  • “发生了一个或多个错误” - 这通常是 AggregateException,它本身并不是很有帮助。确保您检查(并相应地更新您的问题)InnerExceptions 属性以了解真正的问题。
  • 还有一件事:“当 CPU 已经在使用大量功率时”......“这当然是一个较慢的过程,即使是获取值”你不认为这些是(自然)相关?
  • 最佳解决方案可能是根本不执行任何操作,而是通过调用SetProcessWorkingSetSizeEx 让系统强制执行硬限制。根据您使用的系统,可能会有预先构建的解决方案(如Windows System Resource Manager)。

标签: c# windows winforms winapi


【解决方案1】:

不使用 API,一种解决方法是在 C# 中调用以下 PowerShell 命令。

(Get-Counter "\Process(notepad)\Working Set - Private").CounterSamples |
    Sort-Object InstanceName |
        Format-Table InstanceName, @{Label="PrivateWorkingSet"; Expression={$_.CookedValue / 1MB}} -AutoSize

这里我选择记事本作为例子。您可以为每个进程调用此命令来检查私有工作集。

杀死进程:

Stop-Process -Name "notepad"

参考“Executing PowerShell scripts from C#”“Get-Counter - Example 14:Find processes on a computer with the largest working sets

【讨论】:

  • 韩丽塔你好!这是一个非常有趣的方法,但 PowerShell 真的比 C# 更优化/更快吗?
猜你喜欢
  • 2011-04-15
  • 1970-01-01
  • 2023-04-09
  • 2010-09-15
  • 1970-01-01
  • 2022-12-14
  • 1970-01-01
  • 2020-01-19
  • 1970-01-01
相关资源
最近更新 更多