By default, each user process on the 32-bit version of Windows 2000 can have up to a 2 GB private address space; the operating system takes the remaining 2 GB. Windows 2000 Advanced Server and Windows 2000 Datacenter Server support a boot-time option that allows 3-GB user address spaces. These two possible address space layouts are shown in Figure 7-7.
The 3-GB address space option (enabled by the /3GB flag in Boot.ini) gives processes a 3-GB address space (leaving 1 GB for system space). This feature was added as a short-term solution to accommodate the need for applications such as database servers to keep more data in memory than could be done with a 2-GB address space. The AWE functions described earlier in this chapter provide a much better solution to the need for accessing more data than can fit in the limited 2-GB (or 3-GB) process address space.
Figure 7-7 x86 virtual address space layouts
For a process to access the full 3-GB address space, the image file must have the IMAGE_FILE_LARGE_ADDRESS_AWARE flag set in the image header. Otherwise, Windows 2000 reserves the third gigabyte so that the application won't see virtual addresses greater than 0x7FFFFFFF. You set this flag by specifying the linker flag /LARGEADDRESSAWARE when building the executable. This flag has no effect when running the application on a system with a 2-GB user address space. (If you boot Windows 2000 Professional or Windows 2000 Server with the /3GB switch, system space is reduced to 1 GB, but user processes are still limited to 2 GB, even if the large-address-space aware flag is set on an image that is run.)
Virtual Address Space in Consumer Windows
The virtual address space for Windows 95, Windows 98, and Windows Millennium Edition is organized a bit differently from that of Windows 2000. It also provides a 4-GB virtual 32-bit address space, allocating a 2-GB private address space to each process; but it divides the remaining 2 GB between system space (1 GB) and a single shared user space for all shared memory sections (1 GB), as shown here:
The 1-GB shared region is writable from user mode, so any Win32 process can write to shared memory sections or mapped files, even if they don't have that section object (file mapping object in Win32 terms) open. Windows 2000, on the other hand, places shared memory sections inside the private process address space, thus avoiding this security hole. Also, because all MS-DOS and Win16 applications are in this same shared 1-GB region, Win32 processes can corrupt the address space of Win16 and MS-DOS applications in Consumer Windows.
Table 7-6 details the layout of the 2-GB Windows 2000 user process address space.
Table 7-6 Windows 2000 User Process Address Space Layout
|0x0 through 0xFFFF||64 KB||No-access region to aid programmers in avoiding incorrect pointer references; attempts to access an address within this range will cause an access violation. (Note that this range of addresses could be used—this is just a convention to assist in finding bugs.)|
|0x10000 through 0x7FFEFFFF||2 GB minus at least 192 KB||The private process address space.|
|0x7FFDE000 through 0x7FFDEFFF||4 KB||Thread environment block (TEB) for first thread. (See Chapter 6.) Additional TEBs are created at the page prior to this page (starting at address 0x7FFDD000 and working backward).|
|0x7FFDF000 through 0x7FFDFFFF||4 KB||Process environment block (PEB). (See Chapter 6.)|
|0x7FFE0000 through 0x7FFE0FFF||4 KB||Shared user data page. This read-only page is mapped to a page in system space that contains information such as system time, clock tick count, and version number. This page exists so that this data is directly readable from user mode without requiring a kernel-mode transition.|
|0x7FFE1000 through 0x7FFEFFFF||60 KB||No-access region (remainder of 64-KB region following shared user data page).|
|0x7FFF0000 through 0x7FFFFFFF||64 KB||No-access region that prevents threads from passing buffers that straddle the user/system space boundary. MmUserProbeAddress contains the start of this page.|
The system variables shown in Table 7-7 define the range of the user address space.
Table 7-7 Windows 2000 User Address Space System Variables
|System Variable||Description||x86 2-GB User Space||x86 3-GB User Space|
|MmHighestUserAddress||Highest user address (The highest usable address is actually less because of TEBs and PEBs.)||0x7FFEFFFF||0xBFFEFFFF|
|MmUserProbeAddress||Highest user address +1 (used in probing accessibility of user buffers)||0x7FFF0000||0xBFFF0000|
The performance counters listed in Table 7-8 provide information about total system virtual memory utilization.
Table 7-8 Windows 2000 Virtual Memory Use Performance Counters
|Performance Counter||System Variable||Description|
|Memory: Committed Bytes||MmTotalCommittedPages||The amount of committed private address space (of which some can be in physical memory and some in the paging files)|
|Memory: Commit Limit||MmTotalCommitLimit||The amount (in bytes) of memory that can be committed without increasing the size of the paging file (Page files are extensible.)|
|Memory: % Committed Bytes In Use||MmTotalCommittedPages / MmTotalCommitLimit||Ratio of committed bytes to commit limit|
You can obtain the address space utilization of a single process via the process performance counters in Table 7-9.
Table 7-9 Windows 2000 Address Space Use for Single Process's Performance Counters
|Process: Virtual Bytes||Total size of the process address space (including shared as well as private pages)|
|Process: Private Bytes||Size of the private (nonshared) committed address space (same as Process: Page File Bytes)|
|Process: Page File Bytes||Size of the private (nonshared) committed address space (same as Process: Private Bytes)|
|Process: Page File Bytes Peak||Peak of Process: Page File Bytes|
There is also a performance object named Process Address Space that the Performance tool doesn't display. There are 32 counters associated with this object that identify the address space usage of the selected process. For each of the four types of process address space (Image, Mapped, Reserved, and Unassigned), eight separate counters exist (No Access, Read Only, Read/Write, Write Copy, Executable, Exec Read Only, Exec Read/Write, and Exec Write Copy). In addition, there are counters for the total process address space reserved and free. For even more details about user address space layouts, you can query the Image performance object to report per-image (for example, DLLs) memory utilization.
Viewing Process Memory Utilization
Try examining the various process memory performance counters listed in Tables 7-8 and 7-9 with the Performance tool. You can also use several other utilities to examine process physical and virtual memory usage.
For example, start Task Manager (press Ctrl+Shift+Esc), and click the Processes tab. Then from the View menu, choose Select Columns. Select Memory Usage and Virtual Memory Size, and then click OK. You should see a display like this:
Keep in mind that the VM Size column is not the process virtual memory size but rather the process private virtual size (the same as the Process: Private Bytes performance counter described in Table 7-9).
Also, as you'll discover in the section on working sets, the Mem Usage column counts shared pages in each process's memory usage total.
The Process Viewer utility (Pviewer.exe in the Windows 2000 Support Tools; Pview.exe in the Platform SDK) can display per-process address space details. (The source of this utility is one of the Win32 sample programs on MSDN.) From the Start menu, select Programs/Windows 2000 Support Tools/Tools/Process Viewer, select a process, and click the Memory Detail button. You should see something like the following screen shot. Try clicking on the User Address Space For list box—you can select the address space used by the image alone or by loaded DLLs.
This section describes the detailed layout and contents of system space. Figure 7-8 shows the overall structure on x86 systems with a 2-GB system space. (The details of x86 systems with a 1-GB system space are included later in this section.)
Figure 7-8 x86 system space layout (not proportional)
The x86 architecture has the following components in system space:
The rest of this section consists of two tables that list the detailed structure of system space. Table 7-10 lists the kernel variables that contain start and end addresses of various system space regions. Some of these regions are fixed; some are computed at system boot time on the basis of memory size and whether the system is running Windows 2000 Professional or Windows 2000 Server. Table 7-11 lists the structure of system space on x86 systems. Keep in mind that these tables reflect non-PAE systems. Systems running the PAE-enabled kernel image have a slightly different system address space layout.
Table 7-10 System Variables That Describe System Space Regions
|System Variable||Description||x86 2-GB System Space (non-PAE)||x86 1-GB System Space (non-PAE)|
|MmSystemRangeStart||Start address of system space||0x80000000||0xC0000000|
|MmSystemCache-WorkingSetList||System working set list||0xC0C00000||0xC0C00000|
|MmSystemCacheStart||Start of system cache||0xC1000000||0xC1000000|
|MmSystemCacheEnd||End of system cache||Calculated||Calculated|
|MiSystemCacheStart-Extra||Start of system cache or system PTE extension||0xA4000000||0|
|MiSystemCacheEnd-Extra||End of system cache or PTE extension||0xC0000000||0|
|MmPagedPoolStart||Start of paged pool||0xE1000000||0xE1000000|
|MmPagedPoolEnd||End of paged pool||Calculated (maximum size is 482 MB)||Calculated (maximum size is 160 MB)|
|MmNonPagedSystem-Start||Start of system PTEs||Calculated (lowest value is 0xEB000000)||Calculated|
|MmNonPagedPoolStart||Start of nonpaged pool||Calculated||Calculated|
|MmNonPagedPool-ExpansionStart||Start of nonpaged pool expansion||Calculated||Calculated|
|MmNonPagedPoolEnd||End of nonpaged pool||0xFFBE0000||0xFFBE0000|
Table 7-11 x86 System Space (non-PAE)
|0x80000000 through 0x9FFFFFFF||512 MB||System code used to boot the system (Ntoskrnl.exe and Hal.dll) and the initial part of nonpaged pool. On x86 systems with a 2-GB system space and 128 MB or more of RAM, the first 512 MB are mapped using x86 large page PDEs.|
|0xA0000000 through 0xA2FFFFFF||48 MB||System mapped views if Terminal Services not installed; otherwise, session space. (See Table 7-12.)|
|0xA3000000 through 0xA3FFFFFF||16 MB||System mapped views for systems running Terminal Services.|
|0xA4000000 through 0xBFFFFFFF||448 MB||Additional system PTEs (used for kernel stacks, mapping I/O space, and so on) or additional system cache (for systems with large system cache enabled).|
|0xC0000000 through 0xC03FFFFF||4 MB||Process page tables (page directory is at 0xC03000000 and is 4 KB in size). This is per-process data mapped in system space.|
|0xC0400000 through 0xC07FFFFF||4 MB||Working set list and hyperspace. This is per-process data mapped in system space.|
|0xC08000000 through 0xC0BFFFFF||4 MB||Unused.|
|0xC0C00000 through 0xC0FFFFFF||4 MB||System working set list.|
|0xC1000000 through 0xE0FFFFFF||512 MB (maximum)||System cache (size calculated at boot time).|
|0xE1000000 through 0xEAFFFFFF*||160 MB (maximum)||Paged pool (size calculated at boot time).|
|0xEB000000 through 0xFFBDFFFF||331.875 MB (339,840 KB)||System PTEs and nonpaged pool (size calculated at boot time). If the registry PagedPoolSize value is set to -1, system PTEs move from the 0xEB000000 range to the 0xA4000000 range, which lets paged pool grow to use this area ofthe address space.|
|0xFFBE0000 through 0xFFFFFFFF||4.125 MB (4224 KB)||Crash dump structures and private HAL data structures.|
* Because paged pool is limited by the start address of the region containing nonpaged pool and the system PTEs, it can go beyond address 0xEB000000 only if those addresses aren t used.
A session consists of the processes and other system objects (such as the window station, desktops, and windows) that represent a single user's workstation logon session. Each session has a session-specific paged pool area used by the kernel-mode portion of the Win32 subsystem (Win32k.sys) to allocate session-private GUI data structures. In addition, each session has its own copy of the Win32 subsystem process (Csrss.exe) and logon process (Winlogon.exe). The session manager process (Smss.exe) is responsible for creating new sessions, which includes loading a session-private copy of Win32k.sys, creating the session-private object manager namespace, and creating the session-specific instances of the Csrss and Winlogon processes.
To virtualize sessions, all sessionwide data structures are mapped into a region of system space called session space that begins at address 0xA0000000 and extends through address 0xA2FFFFFF. When a process is created, this range of addresses is mapped to the pages appropriate to the session that the process belongs to. Table 7-12 lists the layout of session space on systems with Terminal Services installed.
Table 7-12 Session Space Layout
|0xA0000000 through 0xA07FFFFF||8 MB||Win32k.sys and rebased Windows NT 4 print drivers|
|0xA0800000 through 0xA0BFFFFF||4 MB||MM_SESSION_SPACE structure and session working set lists|
|0xA0C00000 through 0xA1FFFFFF||20 MB||Mapped views for this session|
|0xA2000000 through 0xA2FFFFFF||16 MB||Paged pool for this session|