我正在开发一个基准测试工具,除其他外,它还测量执行操作的外部进程使用的时间和内存。我最感兴趣的是峰值可分页内存大小(a.k.a. PageFileBytesPeak性能计数器/ Process.PeakPagedMemorySize64 /峰值专用字节)。这是一个.NET项目,因此最好使用纯.NET解决方案,但这很可能是不可能的。
这里的问题是我不知道进程退出之前的峰值内存使用情况。当它不再存在时,我无法读取该过程的性能计数器。所以我可以在进程运行时轮询它。
然而,这不是优选的,因为我经常轮询我将干扰完成其工作所需的时间,如果轮询太少,结果将不准确(该过程很可能会触及它退出之前的峰值内存使用率)。所以我希望有一些方法能够可靠地做到这一点,这比我到目前为止提出的解决方案要少得多:
答案 0 :(得分:1)
读取现存的PerfMon计数器应该是一个非常低的开销操作,尤其是。对于你想要使用的系统计数器,因为计数器通常(可能总是?不确定)使用共享内存块(映射文件)实现。
我将使用运行时可配置的时间间隔实现轮询,如果您发现这会严重影响您的应用程序,则只采用更复杂的技术。如果你想首先检查一下,请设置PerfMon以监控感兴趣的计数器,看看在可用的刷新间隔运行时是否会杀死你的应用程序。
答案 1 :(得分:1)
事实证明,只要你有一个活动句柄,GetProcessMemoryInfo即使在进程退出后也能正常工作。如果您碰巧需要,虚拟内存使用情况不可用。
唯一需要注意的是,值的大小取决于调用它的进程的位数,因此如果32位进程测量64位进程的内存使用情况,则值可能会溢出。
示例:
[DllImport("psapi.dll", SetLastError=true)]
static extern bool GetProcessMemoryInfo(IntPtr hProcess, out PROCESS_MEMORY_COUNTERS counters, int size);
[StructLayout(LayoutKind.Sequential)]
private struct PROCESS_MEMORY_COUNTERS
{
public uint cb;
public uint PageFaultCount;
public UIntPtr PeakWorkingSetSize;
public UIntPtr WorkingSetSize;
public UIntPtr QuotaPeakPagedPoolUsage;
public UIntPtr QuotaPagedPoolUsage;
public UIntPtr QuotaPeakNonPagedPoolUsage;
public UIntPtr QuotaNonPagedPoolUsage;
public UIntPtr PagefileUsage;
public UIntPtr PeakPagefileUsage;
}
public long BenchmarkProcessMemoryUsage(string fileName, string arguments)
{
ProcessStartInfo startInfo = new ProcessStartInfo(fileName, arguments);
startInfo.UseShellExecute = false;
Process process = Process.Start();
process.WaitForExit();
PROCESS_MEMORY_COUNTERS counters;
if (!GetProcessMemoryInfo(process.Handle, out counters, Marshal.SizeOf(typeof(PROCESS_MEMORY_COUNTERS))))
throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
return (long)counters.PeakPagefileUsage;
}