You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何仅用WinAPI查询指定进程的私有工作集大小?

不用WMI,纯WinAPI获取进程私有工作集大小

嘿,我完全理解你想绕开WMI、只用原生WinAPI拿到进程私有工作集大小的需求——WMI有时候确实显得笨重又麻烦。你提到GetProcessMemoryInfo()只能拿到总工作集,那咱们来拆解一下用VirtualQueryEx结合QueryWorkingSetEx手动计算的可行方案,其实逻辑没你想的那么复杂,只是需要分步骤梳理清楚。

先明确概念:私有工作集是什么?

私有工作集(Working Set - Private)指的是进程当前加载到物理内存中、且仅被该进程独占使用的内存页总量,和任务管理器里显示的那个数值对应。它和GetProcessMemoryInfo()返回的PrivateUsage(私有字节)不是一回事——后者是进程所有私有虚拟内存的大小,包括不在物理内存里的部分。

核心思路:遍历工作集+判断私有页

要拿到这个值,我们需要两步走:

  1. 获取进程当前的所有工作集页(也就是正在占用物理内存的页)
  2. 对每个页判断是否属于私有内存,最后统计总大小

具体实现步骤&代码示例

1. 获取目标进程的权限句柄

首先得拿到目标进程的句柄,必须申请足够的权限:

#include <windows.h>
#include <psapi.h>
#pragma comment(lib, "psapi.lib")

SIZE_T GetPrivateWorkingSetSize(DWORD dwProcessId) {
    // 申请必要权限:查询进程信息+读取进程内存
    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcessId);
    if (hProcess == NULL) {
        return 0; // 处理错误,比如权限不足
    }

2. 获取工作集信息

用QueryWorkingSetEx()获取整个工作集的页数据,这个函数会返回每个工作集页的虚拟地址和属性:

DWORD dwBufferSize = 0;
    // 先调用一次获取所需缓冲区大小
    QueryWorkingSetEx(hProcess, NULL, dwBufferSize);
    if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
        CloseHandle(hProcess);
        return 0;
    }

    // 分配缓冲区存储工作集信息
    PWS_EX_INFORMATION pWsInfo = (PWS_EX_INFORMATION)malloc(dwBufferSize);
    if (pWsInfo == NULL) {
        CloseHandle(hProcess);
        return 0;
    }

    if (!QueryWorkingSetEx(hProcess, pWsInfo, dwBufferSize)) {
        free(pWsInfo);
        CloseHandle(hProcess);
        return 0;
    }

3. 统计私有工作集大小

遍历每个工作集页,通过WS_EXFLAG_PRIVATE标志直接判断是否为私有页(Vista及以上系统支持),旧系统则用VirtualQueryEx()判断内存类型:

SYSTEM_INFO sysInfo;
    GetSystemInfo(&sysInfo);
    SIZE_T pageSize = sysInfo.dwPageSize; // 获取系统页大小(通常4KB)
    SIZE_T privateWorkingSet = 0;
    DWORD dwPageCount = dwBufferSize / sizeof(WS_EX_INFORMATION);

    for (DWORD i = 0; i < dwPageCount; i++) {
        LPVOID pageAddr = (LPVOID)pWsInfo[i].VirtualAddress;

        // Vista+系统直接用WS_EXFLAG_PRIVATE标志判断,最准确
        if (pWsInfo[i].Flags & WS_EXFLAG_PRIVATE) {
            privateWorkingSet += pageSize;
            continue;
        }

        // 兼容XP及更早系统,用VirtualQueryEx判断内存区域类型
        MEMORY_BASIC_INFORMATION mbi;
        if (VirtualQueryEx(hProcess, pageAddr, &mbi, sizeof(mbi))) {
            // 私有内存区域直接计入
            if (mbi.Type == MEM_PRIVATE) {
                privateWorkingSet += pageSize;
            }
            // 非共享的映射内存也属于私有工作集
            else if (mbi.Type == MEM_MAPPED && !(mbi.Protect & (PAGE_READWRITE_SHARED | PAGE_EXECUTE_READWRITE_SHARED))) {
                privateWorkingSet += pageSize;
            }
        }
    }

4. 清理资源并返回结果

free(pWsInfo);
    CloseHandle(hProcess);
    return privateWorkingSet;
}

关键注意事项

  • 权限问题:必须确保调用OpenProcess时申请了PROCESS_QUERY_INFORMATION和PROCESS_VM_READ权限,否则后续函数会调用失败。
  • 系统兼容性:WS_EXFLAG_PRIVATE是Vista及以后才有的标志,XP系统只能通过内存区域类型判断,准确性稍差但可以接受。
  • 效率问题:遍历整个工作集和内存区域会有一定开销,但针对单个进程来说,这个开销在大多数场景下是可以忽略的。

内容的提问来源于stack exchange,提问作者Krisztián Szabó

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 04:19:35