第14章 探索虚拟内存(1)

14.1 系统信息

(1)获取系统信息GetSystemInfo函数中的SYSTEM_INFO参数

字段

描述

WORD wProcessorArchitecture或

wReserved

联合体。为今后扩展而保留,请勿使用

DWORD dwPageSize

表示CPU页面的大小。在x86和x64机器中,该值为4KB(4096字节),在IA-64机器中,该值为8K字节(8192字节)

LPVOID lpMinimumApplicationAddress

给出每个进程可用地址空间中最小的内存地址。由于每个进程的地址空间中最开始的64KB始终是空闲的,因此该值为65536或0x0000 1000。

LPVOID lpMaximumApplicationAddress

给出每个进程的么有地址空间中最大的可用内存地址

DWORD_PTR dwActiveProcessorMask

一个位掩码,用来表示哪些CPU处于活动状态(即可以用来运行线程)

DWORD dwNumberOfProcessors

表示机器中CPU的数量。双核处理器时该值为2。

DWORD dwProcessorType

己经作废,请勿使用

DWORD dwAllocationGranularity

表示用于预订地址空间区域的分配粒度。该值在Windows平台上都是65536.即64K。即区域的起始地址必须是64KB的整数倍

WORD wProcessorLevel

进一步细分处理器的体系结构。如表示Intel奔腾III或奔腾IV。如果需要确定CPU支持哪些特性,可以调用

IsProcessorFeaturePresent函数,而不是使用这个字段。

WORD wProcessorRevision

进一步对wProcessorLevel进行细分。

(2)IsWow64Process:判断进程是否运行在WOW64环境下,即是否在64位操作系统上运行32位的应用程序。类似于旧的 WOW32 子系统,负责在 Windows 32 位版本下运行 16 位的代码。

参数

描述

HANDLE hProcess

要判断的进程句柄

PBOOL pbWow64Process

TRUE:32位应用程序运行在64位操作系统上

FALSE:32位应用程序运行在32位操作系统或64位应用程序运行在64位的操作系统上。

返回值

FALSE:最常见的原因是传效的参数无效。

TRUE:函数调用成功

备注:

①32位应用程序运行在64位操作系统时,GetSystemInfo得到的dwPageSize为4KB,这种情况下,为了获得64位操作系统实际的系统信息,可以调用GetNativeSystemInfo函数。

②64位应用程序运行在64位操作系统时,GetSystemInfo得到的dwPageSize为8KB。

【SysInfo程序】获取系统信息

/*************************************************************************
Module: SysInfo.cpp
Notices:Copyright(c) 2008 Jeffrey Richter & Christophe Nasarre
*************************************************************************/

#include "../../CommonFiles/CmnHdr.h"
#include "resource.h"
#include <tchar.h>
#include <strsafe.h>

//////////////////////////////////////////////////////////////////////////
//将数据转为字符,并用逗号分开
PTSTR BigNumToString(LONG lNum, PTSTR szBuf, DWORD chBufSize){
    TCHAR szNum[100];
    StringCchPrintf(szNum, _countof(szNum), TEXT("%d"), lNum);
    NUMBERFMT nf;
    nf.NumDigits = 0;
    nf.LeadingZero = FALSE;
    nf.Grouping = 3;//每3位一组
    nf.lpDecimalSep = TEXT(".");
    nf.lpThousandSep = TEXT(",");
    nf.NegativeOrder = 0;
    GetNumberFormat(LOCALE_USER_DEFAULT, 0, szNum, &nf, szBuf, chBufSize);
    return(szBuf);
}

//////////////////////////////////////////////////////////////////////////
//显示对话框标题
void ShowBitness(HWND hwnd){
    TCHAR szFullTitle[100];
    TCHAR szTitle[32];
    GetWindowText(hwnd, szTitle, _countof(szTitle));

#if defined(_WIN64)
    //64位的应用程序只能运行在64位的操作系统上
    //因此,这里不需要特殊的检查
    StringCchPrintf(szFullTitle, _countof(szFullTitle), TEXT("64位'%s'"), szTitle);
#else
    BOOL bIsWow64 = FALSE;
    if (!IsWow64Process(GetCurrentProcess(),&bIsWow64)){
        chFAIL("获取WOW64状态失败!");
        return;
    }

    if (bIsWow64){
        StringCchPrintf(szFullTitle, _countof(szFullTitle), TEXT("32位程序'%s'运行在64位OS上"), szTitle);
    } else{
        StringCchPrintf(szFullTitle, _countof(szFullTitle), TEXT("32位程序'%s'运行在32位OS上"), szTitle);
    }
#endif
    SetWindowText(hwnd, szFullTitle);
}


//////////////////////////////////////////////////////////////////////////
//显示CPU信息
void ShowCPUInfo(HWND hwnd, WORD wProcessorArchitecture, WORD wProcessorLevel,
                 WORD wProcessorRevision){
    TCHAR szCPUArch[64] = TEXT("(未知)");
    TCHAR szCPULevel[64] = TEXT("(未知)");
    TCHAR szCPURev[64] = TEXT("(未知)");

    switch (wProcessorArchitecture)
    {
        //注意:AMD处理器被视为PROCESSOR_ARCHITECTUR_INTEL,在注册表的
        //HKLMHARDWAREDESCRIPTIONSystemCentralProcessor下的"VendorIdentifier"(代应商ID)
        //键的值为 "GenuineIntel" 或"AuthenticAMD"
    
    case PROCESSOR_ARCHITECTURE_INTEL:
        {
            _tcscpy_s(szCPUArch, _countof(szCPUArch), TEXT("Intel"));
            switch (wProcessorLevel)
            {
            case 3:
            case 4: //80386或80486
                StringCchPrintf(szCPULevel, _countof(szCPULevel), TEXT("80%c86"), wProcessorLevel + '0');
                StringCchPrintf(szCPURev, _countof(szCPURev), TEXT("%c%d"), 
                                HIBYTE(wProcessorRevision)+TEXT('A'),
                                LOBYTE(wProcessorRevision));
                break;
                
            case 5:
                _tcscpy_s(szCPULevel, _countof(szCPULevel), TEXT("奔腾"));
                StringCchPrintf(szCPURev, _countof(szCPURev), TEXT("Model %d,Stepping d"), 
                                HIBYTE(wProcessorRevision),
                                LOBYTE(wProcessorRevision));
                break;

            case 6:
                switch (HIBYTE(wProcessorRevision)) //Model
                {
                case 1:
                    _tcscpy_s(szCPULevel, _countof(szCPULevel), TEXT("奔腾 Pro"));
                    break;
                case 3:
                case 5:
                    _tcscpy_s(szCPULevel, _countof(szCPULevel), TEXT("奔腾 II"));
                    break;

                case 6:
                    _tcscpy_s(szCPULevel, _countof(szCPULevel), TEXT("赛扬"));
                    break;
                case 7:
                case 8:
                case 11:
                    _tcscpy_s(szCPULevel, _countof(szCPULevel), TEXT("奔腾 III"));
                    break;

                case 9:
                case 13:
                    _tcscpy_s(szCPULevel, _countof(szCPULevel), TEXT("奔腾 M"));
                    break;

                case 10:
                    _tcscpy_s(szCPULevel, _countof(szCPULevel), TEXT("奔腾 至强"));
                    break;

                case 15:
                    _tcscpy_s(szCPULevel, _countof(szCPULevel), TEXT("Core 2 Duo"));
                    break;
                default:
                    _tcscpy_s(szCPULevel, _countof(szCPULevel), TEXT("未知奔腾"));
                    break;
                }
                StringCchPrintf(szCPURev, _countof(szCPURev), TEXT("Model %d,Stepping %d"), 
                                HIBYTE(wProcessorRevision),LOBYTE(wProcessorRevision));
                break;

            case 15:
                _tcscpy_s(szCPULevel, _countof(szCPULevel), TEXT("奔腾 4"));
                StringCchPrintf(szCPURev, _countof(szCPURev), TEXT("Model %d,Stepping %d"),
                                HIBYTE(wProcessorRevision), LOBYTE(wProcessorRevision));
                break;
            }
        }
        break;

    case PROCESSOR_ARCHITECTURE_IA64:
        _tcscpy_s(szCPULevel, _countof(szCPULevel), TEXT("IA-64"));
        StringCchPrintf(szCPULevel, _countof(szCPULevel), TEXT("%d"), wProcessorLevel);
        StringCchPrintf(szCPURev, _countof(szCPURev), TEXT("Model %c,Pass %d"),
                        HIBYTE(wProcessorRevision)+TEXT('A'),
                        LOBYTE(wProcessorRevision));
        break;

    case PROCESSOR_ARCHITECTURE_AMD64:
        _tcscpy_s(szCPULevel, _countof(szCPULevel), TEXT("AMD64"));
        StringCchPrintf(szCPULevel, _countof(szCPULevel), TEXT("%d"), wProcessorLevel);
        StringCchPrintf(szCPURev, _countof(szCPURev), TEXT("Model %c,Pass %d"),
                        HIBYTE(wProcessorRevision) + TEXT('A'),
                        LOBYTE(wProcessorRevision));
        break;
    case PROCESSOR_ARCHITECTURE_UNKNOWN:
    default:
        _tcscpy_s(szCPUArch, _countof(szCPUArch), TEXT("未知"));
        break;
    }

    SetDlgItemText(hwnd, IDC_PROCARCH, szCPUArch);
    SetDlgItemText(hwnd, IDC_PROCLEVEL, szCPULevel);
    SetDlgItemText(hwnd, IDC_PROCREV, szCPURev);
}

//////////////////////////////////////////////////////////////////////////
BOOL Dlg_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam){

    chSETDLGICONS(hwnd, IDI_SYSINFO);

    //获得系统信息
    SYSTEM_INFO  sinf;
    GetSystemInfo(&sinf);

    //显示CPU信息
    ShowCPUInfo(hwnd, sinf.wProcessorArchitecture, sinf.wProcessorLevel,
                sinf.wProcessorRevision);

    //显示页面大小
    TCHAR szBuf[50];
    SetDlgItemText(hwnd, IDC_PAGESIZE, BigNumToString(sinf.dwPageSize, szBuf, _countof(szBuf)));

    //显示进程可用的最小地址
    StringCchPrintf(szBuf, _countof(szBuf), TEXT("0x%p"), sinf.lpMinimumApplicationAddress);
    SetDlgItemText(hwnd, IDC_MINAPPADDR, szBuf);

    //显示进程可用的最大地址
    StringCchPrintf(szBuf, _countof(szBuf), TEXT("0x%p"), sinf.lpMaximumApplicationAddress);
    SetDlgItemText(hwnd, IDC_MAXAPPADDR, szBuf);

    //显示CPU掩码位
    StringCchPrintf(szBuf, _countof(szBuf), TEXT("0x%016I64X"),(__int64) sinf.dwActiveProcessorMask);
    SetDlgItemText(hwnd, IDC_ACTIVEPROCMASK, szBuf);

    //显示CPU核数
    SetDlgItemText(hwnd, IDC_NUMOFPROCS, BigNumToString(sinf.dwNumberOfProcessors, szBuf, _countof(szBuf)));
    
    //分配粒度
    SetDlgItemText(hwnd, IDC_ALLOCGRAN, BigNumToString(sinf.dwAllocationGranularity, szBuf, _countof(szBuf)));
    
    //显示对话框标题
    ShowBitness(hwnd);
    return TRUE;
}

//////////////////////////////////////////////////////////////////////////
void Dlg_OnCommand(HWND hwnd, int id, HWND hwndCtrl, UINT codeNotity){
    switch (id)
    {
    case IDCANCEL:
        EndDialog(hwnd, id);
        break;
    }
}


//////////////////////////////////////////////////////////////////////////
INT_PTR WINAPI Dlg_Proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
    switch (uMsg)
    {
        chHANDLE_DLGMSG(hwnd, WM_INITDIALOG, Dlg_OnInitDialog);
        chHANDLE_DLGMSG(hwnd, WM_COMMAND, Dlg_OnCommand);
    }
    return FALSE;
}

//////////////////////////////////////////////////////////////////////////
int WINAPI _tWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, _In_ int nShowCmd)
{
    DialogBox(hInstance, MAKEINTRESOURCE(IDD_SYSINFO), NULL, Dlg_Proc);
    return 0;
}

//resource.h

//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ 生成的包含文件。
// 供 14_SysInfo.rc 使用
//
#define IDD_SYSINFO                     1
#define IDC_PROCARCH                    100
#define IDC_PAGESIZE                    101
#define IDC_MINAPPADDR                  102
#define IDC_MAXAPPADDR                  103
#define IDC_ACTIVEPROCMASK              104
#define IDC_NUMOFPROCS                  105
#define IDC_PROCTYPE                    106
#define IDC_ALLOCGRAN                   107
#define IDC_PROCLEVEL                   108
#define IDC_PROCREV                     109
#define IDI_SYSINFO                     110
// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        103
#define _APS_NEXT_COMMAND_VALUE         40001
#define _APS_NEXT_CONTROL_VALUE         1001
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif

//SysInfo.rc

// Microsoft Visual C++ generated resource script.
//
#include "resource.h"

#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"

/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS

/////////////////////////////////////////////////////////////////////////////
// 中文(简体,中国) resources

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED

#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//

1 TEXTINCLUDE 
BEGIN
    "resource.h"
END

2 TEXTINCLUDE 
BEGIN
    "#include ""winres.h""
"
    ""
END

3 TEXTINCLUDE 
BEGIN
    "
"
    ""
END

#endif    // APSTUDIO_INVOKED


/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//

IDD_SYSINFO DIALOGEX 0, 0, 173, 108
STYLE DS_SETFONT | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "系统信息"
FONT 10, "宋体", 400, 0, 0x86
BEGIN
    RTEXT           "处理器架构:",IDC_STATIC,10,8,68,8,SS_NOPREFIX
    RTEXT           "ID_PROCARCH",IDC_PROCARCH,81,8,80,8,SS_NOPREFIX
    RTEXT           "处理器级别:",IDC_STATIC,10,18,68,8,SS_NOPREFIX
    RTEXT           "ID_PROCLEVEL",IDC_PROCLEVEL,81,18,80,8,SS_NOPREFIX
    RTEXT           "处理器修订版本:",IDC_STATIC,10,28,68,8,SS_NOPREFIX
    RTEXT           "ID_PROCREV",IDC_PROCREV,81,28,80,8,SS_NOPREFIX
    RTEXT           "处理器的数量:",IDC_STATIC,10,38,68,8,SS_NOPREFIX
    RTEXT           "ID_NUMOFPROCS",IDC_NUMOFPROCS,81,38,80,8,SS_NOPREFIX
    RTEXT           "可用处理器掩码:",IDC_STATIC,10,48,68,8,SS_NOPREFIX
    RTEXT           "ID_ACTIVEPROCMASK",IDC_ACTIVEPROCMASK,81,48,80,8,SS_NOPREFIX
    RTEXT           "分配粒度(字节):",IDC_STATIC,10,58,68,8,SS_NOPREFIX
    RTEXT           "ID_ALLOCGRAN",IDC_ALLOCGRAN,81,58,80,8,SS_NOPREFIX
    RTEXT           "页面大小(字节):",IDC_STATIC,10,68,68,8,SS_NOPREFIX
    RTEXT           "ID_PAGESIZE",IDC_PAGESIZE,81,68,80,8,SS_NOPREFIX
    RTEXT           "进程可用最小地址:",IDC_STATIC,10,78,68,8,SS_NOPREFIX
    RTEXT           "ID_MINAPPADDR",IDC_MINAPPADDR,81,78,80,8,SS_NOPREFIX
    RTEXT           "进程可用最大地址:",IDC_STATIC,10,88,68,8,SS_NOPREFIX
    RTEXT           "ID_MAXAPPADDR",IDC_MAXAPPADDR,81,88,80,8,SS_NOPREFIX
END


/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//

#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
    IDD_SYSINFO, DIALOG
    BEGIN
        LEFTMARGIN, 7
        RIGHTMARGIN, 166
        TOPMARGIN, 7
        BOTTOMMARGIN, 101
    END
END
#endif    // APSTUDIO_INVOKED


/////////////////////////////////////////////////////////////////////////////
//
// Icon
//

// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_SYSINFO             ICON                    "SysInfo.ico"
#endif    // 中文(简体,中国) resources
/////////////////////////////////////////////////////////////////////////////



#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//


/////////////////////////////////////////////////////////////////////////////
#endif    // not APSTUDIO_INVOKED

14.2 虚拟内存状态——GlobalMemoryStatus函数

(1)GlobalMemoryStatus函数(16位遗留的历史问题,可理解为VirtualMemoryStatus)

  ①VOID GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer);

  ②MEMORYSTATUS结构体

字段

描述

DWORD dwLength

结构体大小,等于sizeof(MEMORYSTATUS)。调用函数之前,必须初始化该成员

DWORD dwMemoryLoad

己用内存的百分比,介于0-100之间。

SIZE_T dwTotalPhys

物理内存总量(以字节为单位)

SIZE_T dwAvailPhys

可用物理内存(以字节为单位)

SIZE_T dwTotalPageFile

页交换文件总的大小

SIZE_T dwAvailPageFile

页交换文件中空闲部分的大小

SIZE_T dwTotalVirtual

用户可用的地址空间,即进程私有的那部分地址空间。

SIZE_T dwAvailVitual

当前空闲的地址空间。(注意这个成员是唯一与该进程有关的成员,所有其他成员适用于整个系统)。函数会将调用进程的地址空间中所有空闲的区域加起来

  ③该函数不支持物理内存或页交换文件大于4GB的情况。

(2)GlobalMemoryStatusEx函数——支持内存大于4GB

  ①BOOL GlobalMemoryStatusEx(LPMEMORYSTATUSEX pmst);

  ②MEMORYSTATUSEX 结构体—与MEMORYSTATUSEX结构体中各字段的含义相同,但所有表示大小的字段都由SIZE_T改为DWORDLONG型,即64位,可以容纳大于4GB的值

(3)获得进程的工作集

  ①工作集(WorkingSet):用来表示当前进程正在使用的物理存储器的数量。我们把一个进程的地址空间中被保存在内存里的那些页面称为它的工作集。

  ②GetProcessMemoryInfo(HANDLE hProcess,PROCESS_MEMORY_COUNTERS ppmc,DWORD cbSize);//定义在psapi.h头文件中(注意cbSize等于sizeof(PROCESS_MEMORY_COUNTERS))。

  ③PROCESS_MEMORY_COUNTERS_EX结构体

字段

描述

DWORD cb

结构体的大小

DWORD PageFaultCount

缺页中断次数

SIZE_T PeakWorkingSetSize

使用内存高峰值,自进程开始运行以来,曾经使用过的内存数量的最大值(字节)

SIZE_T WorkingSetSize

当前使用的内存。函数被调用时,进程正在使用的字节数(字节)

SIZE_T QuotaPeakPagedPoolUsage

使用页面缓存池高峰(字节)

SIZE_T QuotaPagedPoolUsage

当前使用页面缓存池(字节)

SIZE_T QuotaPeakNonPagedPoolUsage

使用非分页缓存池高峰(字节)

SIZE_T QuotoNonPagedPoolUsage

当前使用非分页缓存池(字节)

SIZE_T PagefileUsage

当前使用分页文件(字节)

SIZE_T PeakPagefileUsage

使用分页文件的高峰(字节)

SIZE_T PrivateUsage

应用程序调用new、malloc或VirtualAlloc函数来显式地分配了多少内存。

14.3 NUMA机器中的内存管理

 

多核环境中的NUMA架构示意图

(1)非统一内存访问:(Non-Uniform Memory Access,NUMA)机器中的CPU即能访问自己节点的内存,也能访问其他节点的内存,虽然访问自己节点内存的速度要比访问外节点的内存要快得多。默认当线程提交物理存储器时,操作系统会尽量用CPU自己节点的内存来支持物理存储器。但如果没有足够的内存,也会使用外节点内存来支持物理存储器。

(2)调用GlobalMemoryStatusEx函数时,ullAvailPhys参数返回的值是所有节点的可用内存的总量。

(3)获取某个特定NUMA节点的内存数量的方法:

  ①调用GetNumaAvailableMemoryNode(UCHAR uNode,PULONGLONG pulAvailableBytes);参数uNode用来标识节点,参数pulAvailableBytes返回该节点的内存数量。

  ②获取CPU驻留在哪个NUMA节点:GetNumaProcessorNode(UCHAR Processor,PUCHAR NodeNumber);

  ③获取系统中节点总数:GetNumaHighestNodeNumber(PULONG pulHighestNodeNumber);

  ④获取某个节点的CPU列表:GetNumaNodeProcessorMask(UCHAR uNode,PULONGLONG pulProcessorMask);参数uNode是节点的数字标识,参数pulProcessorMask所指向的ULONGLONG变量用来返回位掩码,如果某一位被设置,表示该位对位的CPU就属于该节点。

 【VMStat程序】显示当前内存状态信息

/*************************************************************************
Module: VMStat.cpp
Notices:Copyright(c) 2008 Jeffrey Richter & Christophe Nasarre
*************************************************************************/

#include "../../CommonFiles/CmnHdr.h"
#include "resource.h"
#include <Psapi.h> //供GetProcessMemoryInfo函数使用
#include <tchar.h>
#include <strsafe.h>


//////////////////////////////////////////////////////////////////////////
#pragma  comment(lib,"psapi.lib") //静态链接psapi.dll文件
//////////////////////////////////////////////////////////////////////////
//计时器ID
#define IDT_UPDATE 1

//////////////////////////////////////////////////////////////////////////
BOOL Dlg_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam){
    chSETDLGICONS(hwnd, IDI_VMSTAT);

    //设置计时器,以便周期性地更新内存状态信息
    SetTimer(hwnd, IDT_UPDATE, 1 * 1000, NULL);

    //强制计时器发送更新消息
    FORWARD_WM_TIMER(hwnd, IDT_UPDATE, SendMessage); //立即更新一下

    return TRUE;
}

//////////////////////////////////////////////////////////////////////////
void Dlg_OnTimer(HWND hwnd, UINT id){
    //初始化结构体
    MEMORYSTATUSEX ms = { sizeof(ms) };
    GlobalMemoryStatusEx(&ms);

    TCHAR szData[512] = { 0 };
    StringCchPrintf(szData, _countof(szData),
        TEXT("%d
%I64d
%I64d
%I64d
%I64d
%I64d
%I64d
"),
        ms.dwMemoryLoad,
        ms.ullTotalPhys,
        ms.ullAvailPhys,
        ms.ullTotalPageFile,
        ms.ullAvailPageFile,
        ms.ullTotalVirtual,
        ms.ullAvailVirtual);

    SetDlgItemText(hwnd, IDC_DATA, szData);

    //获取当前进程工作集和私有地址空间
    PROCESS_MEMORY_COUNTERS_EX pmc = { sizeof(pmc) };
    GetProcessMemoryInfo(GetCurrentProcess(), (PPROCESS_MEMORY_COUNTERS)&pmc, sizeof(pmc));
    StringCchPrintf(szData, _countof(szData), 
                    TEXT("%I64d KB
%I64d KB"),
                    (__int64)pmc.WorkingSetSize /1024,
                    (__int64)pmc.PrivateUsage /1024);
    SetDlgItemText(hwnd, IDC_PROCESSDATA, szData);
}

//////////////////////////////////////////////////////////////////////////
void Dlg_OnCommand(HWND hwnd, int id, HWND hwndCtrl, UINT codeNotify){
    switch (id)
    {
    case IDCANCEL:
        KillTimer(hwnd, IDT_UPDATE);
        EndDialog(hwnd, id);
        break;
    }
}

//////////////////////////////////////////////////////////////////////////
INT_PTR WINAPI Dlg_Proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        chHANDLE_DLGMSG(hwnd, WM_INITDIALOG, Dlg_OnInitDialog);
        chHANDLE_DLGMSG(hwnd, WM_COMMAND, Dlg_OnCommand);
        chHANDLE_DLGMSG(hwnd, WM_TIMER, Dlg_OnTimer);
    }
    return FALSE;
}

//////////////////////////////////////////////////////////////////////////
int WINAPI _tWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, _In_ int nShowCmd)
{
    DialogBox(hInstance, MAKEINTRESOURCE(IDD_VMSTAT), NULL, Dlg_Proc);
    return 0;
}

//resource.h

//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ 生成的包含文件。
// 供 14_VMStat.rc 使用
//
#define IDD_VMSTAT                      1
#define IDI_VMSTAT                      101
#define IDI_ICON1                       102
#define IDC_DATA                        1000
#define IDC_WORKINGSET                  1001
#define IDC_PROCESSDATA                 1001

// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        103
#define _APS_NEXT_COMMAND_VALUE         40001
#define _APS_NEXT_CONTROL_VALUE         1001
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif

//VMStat.rc

// Microsoft Visual C++ generated resource script.
//
#include "resource.h"

#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"

/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS

/////////////////////////////////////////////////////////////////////////////
// 中文(简体,中国) resources

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED

#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//

1 TEXTINCLUDE 
BEGIN
    "resource.h"
END

2 TEXTINCLUDE 
BEGIN
    "#include ""winres.h""
"
    ""
END

3 TEXTINCLUDE 
BEGIN
    "
"
    ""
END

#endif    // APSTUDIO_INVOKED


/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//

IDD_VMSTAT DIALOGEX 0, 0, 174, 102
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "内存状态信息"
FONT 10, "宋体", 400, 0, 0x86
BEGIN
    LTEXT           "己用内存(%):
物理内存总数(字节):
可用物理内存(字节):
交换文件总数(字节):
交换文件空闲总数(字节):
用户可用地址空间:
当前空闲地址空间:",IDC_STATIC,9,8,91,56,0,WS_EX_RIGHT
    RTEXT           "Memory load:
TotalPhys:
AvailPhys:
TotalPageFile:
AvailPageFile:
TotalVirtual:
AvailVirtual:",IDC_DATA,102,8,61,56
    LTEXT           "当前进程工作集:
私有地址空间:",IDC_STATIC,17,74,67,17,0,WS_EX_RIGHT
    LTEXT           "WorkingSet:
PrivateBytes:",IDC_PROCESSDATA,86,74,61,17,0,WS_EX_RIGHT
    CONTROL         "",IDC_STATIC,"Static",SS_ETCHEDFRAME,9,70,158,1
END


/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//

#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
    IDD_VMSTAT, DIALOG
    BEGIN
        LEFTMARGIN, 7
        RIGHTMARGIN, 167
        TOPMARGIN, 7
        BOTTOMMARGIN, 95
    END
END
#endif    // APSTUDIO_INVOKED


/////////////////////////////////////////////////////////////////////////////
//
// Icon
//

// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_VMSTAT              ICON                    "VMStat.ico"
#endif    // 中文(简体,中国) resources
/////////////////////////////////////////////////////////////////////////////



#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//


/////////////////////////////////////////////////////////////////////////////
#endif    // not APSTUDIO_INVOKED
原文地址:https://www.cnblogs.com/5iedu/p/4852712.html