Working Set, Paged Pool and Non-paged pool

来源:互联网 发布:手机贴膜有必要吗 知乎 编辑:程序博客网 时间:2024/05/16 00:36

Working Set

The working set of a process is the set of pages in the virtual address space of the process that are currently resident in physical memory. The working set contains only pageable memory allocations; nonpageable memory allocations such as Address Windowing Extensions (AWE) or large page allocations are not included in the working set.

When a process references pageable memory that is not currently in its working set, a page fault occurs. The system page fault handler attempts to resolve the page fault and, if it succeeds, the page is added to the working set. (Accessing AWE or large page allocations never causes a page fault, because these allocations are not pageable .)

查看工作集可以知道进程稳定运行时需要使用多少的物理内存。


Nonpaged Pool

The kernel and device drivers use nonpaged pool to store data that might be accessed when the system can’t handle page faults. The kernel enters such a state when it executes interrupt service routines (ISRs) and deferred procedure calls (DPCs), which are functions related to hardware interrupts. Page faults are also illegal when the kernel or a device driver acquires a spin lock, which, because they are the only type of lock that can be used within ISRs and DPCs, must be used to protect data structures that are accessed from within ISRs or DPCs and either other ISRs or DPCs or code executing on kernel threads. Failure by a driver to honor these rules results in the most common crash code, IRQL_NOT_LESS_OR_EQUAL.

Nonpaged pool is therefore always kept present in physical memory and nonpaged pool virtual memory is assigned physical memory. Common system data structures stored in nonpaged pool include the kernel and objects that represent processes and threads, synchronization objects like mutexes, semaphores and events, references to files, which are represented as file objects, and I/O request packets (IRPs), which represent I/O operations.

非换页池是系统中极其重要的资源,非换页池的内存紧张会导致系统各种异常行为,例如http.sys会拒绝请求,从而IIS无法对外提供服务,C:\Windows\System32\LogFiles\HTTPERR 中会记录Connections_Refused。代表内核 NonPagedPool 内存已下降到 20MB 以下,http.sys 已停止接收新连接。


Paged Pool

Paged pool, on the other hand, gets its name from the fact that Windows can write the data it stores to the paging file, allowing the physical memory it occupies to be repurposed. Just as for user-mode virtual memory, when a driver or the system references paged pool memory that’s in the paging file, an operation called a page fault occurs, and the memory manager reads the data back into physical memory. The largest consumer of paged pool, at least on Windows Vista and later, is typically the Registry, since references to registry keys and other registry data structures are stored in paged pool. The data structures that represent memory mapped files, called sections internally, are also stored in paged pool.

Device drivers use the ExAllocatePoolWithTag API to allocate nonpaged and paged pool, specifying the type of pool desired as one of the parameters. Another parameter is a 4-byte Tag, which drivers are supposed to use to uniquely identify the memory they allocate, and that can be a useful key for tracking down drivers that leak pool, as I’ll show later.


最简单的查看系统进程相应的内存信息的方式是打开task manager - 然后选择working set, paged pool, non-paged pool列来查看每个进程的使用情况。


下面一段程序也可以输出系统运行的进程中相应的working set, paged pool, non-paged pool信息。

#include <windows.h>#include <stdio.h>#include <psapi.h>// To ensure correct resolution of symbols, add Psapi.lib to TARGETLIBS// and compile with -DPSAPI_VERSION=1void PrintMemoryInfo( DWORD processID ){    HANDLE hProcess;    PROCESS_MEMORY_COUNTERS pmc;    // Print the process identifier.    printf( "\nProcess ID: %u\n", processID );    // Print information about the memory usage of the process.    hProcess = OpenProcess(  PROCESS_QUERY_INFORMATION |                                    PROCESS_VM_READ,                                    FALSE, processID );    if (NULL == hProcess)        return;    if ( GetProcessMemoryInfo( hProcess, &pmc, sizeof(pmc)) )    {        printf( "\tPageFaultCount: 0x%08X\n", pmc.PageFaultCount );        printf( "\tPeakWorkingSetSize: 0x%08X\n",                   pmc.PeakWorkingSetSize );        printf( "\tWorkingSetSize: 0x%08X\n", pmc.WorkingSetSize );        printf( "\tQuotaPeakPagedPoolUsage: 0x%08X\n",                   pmc.QuotaPeakPagedPoolUsage );        printf( "\tQuotaPagedPoolUsage: 0x%08X\n",                   pmc.QuotaPagedPoolUsage );        printf( "\tQuotaPeakNonPagedPoolUsage: 0x%08X\n",                   pmc.QuotaPeakNonPagedPoolUsage );        printf( "\tQuotaNonPagedPoolUsage: 0x%08X\n",                   pmc.QuotaNonPagedPoolUsage );        printf( "\tPagefileUsage: 0x%08X\n", pmc.PagefileUsage );         printf( "\tPeakPagefileUsage: 0x%08X\n",                   pmc.PeakPagefileUsage );    }    CloseHandle( hProcess );}int main( void ){    // Get the list of process identifiers.    DWORD aProcesses[1024], cbNeeded, cProcesses;    unsigned int i;    if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) )    {        return 1;    }    // Calculate how many process identifiers were returned.    cProcesses = cbNeeded / sizeof(DWORD);    // Print the memory usage for each process    for ( i = 0; i < cProcesses; i++ )    {        PrintMemoryInfo( aProcesses[i] );    }    return 0;}


原创粉丝点击