0

我正在开发一个基准工具,其中包括测量执行操作的外部进程使用的时间和内存。我最感兴趣的是峰值可分页内存大小(又名 PageFileBytesPeak 性能计数器 / Process.PeakPagedMemorySize64 / 峰值私有字节)。这是一个 .NET 项目,因此最好使用纯 .NET 解决方案,但这很可能是不可能的。

这里的问题是在进程退出之前我不会知道峰值内存使用量。当进程不再存在时,我无法读取进程的性能计数器。所以我可以在进程运行时轮询它。

但是,这并不可取,因为如果我轮询太频繁,我会干扰进程完成其工作所需的时间,如果轮询太少,结果将不准确(该进程很可能会达到其内存使用峰值就在它退出之前)。所以我希望有一些方法可以可靠地做到这一点,它比我迄今为止提出的解决方案更简单:

  1. 将DLL注入进程,通过DLL_PROCESS_DETACH上的IPC机制报告值。
  2. 目标进程中的Patch/Hook ExitProcess,在执行真正的ExitProcess之前通过IPC机制上报值。
  3. 假装是调试器,测量 EXIT_PROCESS_DEBUG_EVENT 上的值(在调用 ContinueDebugEvent 之前,内核不会清理该进程)。
4

2 回答 2

1

读取现存的 PerfMon 计数器应该是一个非常低开销的操作,尤其是。对于您想要使用的系统计数器,因为计数器通常(可能总是?不确定)使用共享内存块(映射文件)实现。

我会使用运行时可配置的时间间隔来实现轮询,并且只有在您发现这对您的应用程序产生重大影响时才使用更复杂的技术。如果您想首先对此进行全面检查,请设置 PerfMon 以监视感兴趣的计数器,并查看在以可用刷新间隔运行时是否会杀死您的应用程序。

于 2013-03-22T17:06:28.837 回答
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;
}
于 2013-03-26T16:55:37.567 回答