---
title: "Windows C++ 获取进程内存使用情况"
author: "Perrin Yong"
author_profile: https://www.pystone.net/profile/
published_by: "Perrin Yong"
canonical: https://www.pystone.net/notes/cpp-windows-process-memory-usage/
type: note
content_role: unspecified
visibility: public
id_stability: rename-stable
source_path: "10-计算机、信息技术与工程/02-编程语言与运行时/C++/C++获取内存使用情况.md"
content_hash: 4f69353219f55760f4e41c7da657b7c9cf6b30979ac2df4644f373cfab945d06
knowledge_version: 224c990773de.5fa8af6e39fa
site_commit: 224c990773de166d23a886306577dd90379529ce
notes_commit: 5fa8af6e39fa3891d1b9b4832bfa6c4e0ecaaf0a
---
# Windows C++ 获取进程内存使用情况

> 创建时间：2020/5/14 22:18

Windows 可通过 PSAPI 的 `GetProcessMemoryInfo` 读取进程内存计数器。常用字段包括：

- `WorkingSetSize`：当前驻留在物理内存中的工作集；其中可能包含共享页面。
- `PeakWorkingSetSize`：进程生命周期内的工作集峰值。
- `PrivateUsage`：`PROCESS_MEMORY_COUNTERS_EX` 提供的私有提交量，更接近该进程独自承担的已提交内存，但仍不等同于所有分析工具中的 “private working set”。
- `PageFaultCount`：累计缺页次数，不能单独代表性能问题。

不同工具的“内存占用”可能采用工作集、私有工作集、提交量或 PSS 等不同口径，比较前必须确认定义。

## 查询当前进程

```cpp
#include <windows.h>
#include <psapi.h>

#include <cstddef>
#include <iostream>

#pragma comment(lib, "psapi.lib")

int main() {
    PROCESS_MEMORY_COUNTERS_EX counters{};
    counters.cb = sizeof(counters);

    const BOOL ok = GetProcessMemoryInfo(
        GetCurrentProcess(),
        reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&counters),
        sizeof(counters));

    if (!ok) {
        std::cerr << "GetProcessMemoryInfo failed, error="
                  << GetLastError() << '\n';
        return 1;
    }

    constexpr std::size_t MiB = 1024 * 1024;
    std::cout << "Working set: "
              << counters.WorkingSetSize / MiB << " MiB\n";
    std::cout << "Peak working set: "
              << counters.PeakWorkingSetSize / MiB << " MiB\n";
    std::cout << "Private commit: "
              << counters.PrivateUsage / MiB << " MiB\n";
}
```

## 查询指定 PID

打开其他进程时只申请查询所需的最小权限，并检查句柄与 API 返回值：

```cpp
#include <windows.h>
#include <psapi.h>

#include <iostream>

#pragma comment(lib, "psapi.lib")

bool PrintProcessMemory(DWORD processId) {
    HANDLE process = OpenProcess(
        PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ,
        FALSE,
        processId);

    if (process == nullptr) {
        std::cerr << "OpenProcess failed, error=" << GetLastError() << '\n';
        return false;
    }

    PROCESS_MEMORY_COUNTERS_EX counters{};
    counters.cb = sizeof(counters);
    const BOOL ok = GetProcessMemoryInfo(
        process,
        reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&counters),
        sizeof(counters));

    if (ok) {
        std::cout << "PID " << processId
                  << ", working set=" << counters.WorkingSetSize
                  << " bytes, private commit=" << counters.PrivateUsage
                  << " bytes\n";
    } else {
        std::cerr << "GetProcessMemoryInfo failed, error="
                  << GetLastError() << '\n';
    }

    CloseHandle(process);
    return ok == TRUE;
}
```

某些受保护进程无法读取，提升到 `SeDebugPrivilege` 也不是通用解决方案。工具应正常处理访问被拒绝，并避免默认以管理员身份运行。

## 分析建议

1. 固定构建、场景和采样时间，重复采样而非只看单点。
2. 同时记录工作集、私有提交量和系统整体内存压力。
3. 排查泄漏时结合堆快照、分配调用栈和对象生命周期。
4. 64 位大小使用 `SIZE_T`/`std::size_t`，避免用 `%d` 截断。
5. 句柄必须关闭；动态数组应使用标准容器或 RAII，避免手工 `new[]`/`delete[]` 错配。

## 参考资料

- [Microsoft Learn：GetProcessMemoryInfo](https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getprocessmemoryinfo)
- [Microsoft Learn：Process Memory Usage Information](https://learn.microsoft.com/en-us/windows/win32/psapi/process-memory-usage-information)
