MMSUPPORT

Though it’s hardly clear from its name, the MMSUPPORT structure (formally _MMSUPPORT) is the Memory Manager’s highest-level implementation of a Working Set. It may best be thought of as an organising container. The main work is implemented in the MMWSL (Working Set List) structure and its potentially large array of MMWSLE (Working Set List Entry) structures.

Working sets come in five types. An MMSUPPORT for a process working set is embedded in each EPROCESS as the Vm member. A session working set is represented by an MMSUPPORT structure in the session’s MM_SESSION_SPACE (again as a member named Vm). Three system-wide working sets have MMSUPPORT structures in the kernel’s data section, as the internal variables that symbol files for the kernel used to name MmSystemCacheWs, MmPagedPoolWs and MmSystemPtesWs.

The 1607 release of Windows 10 discontinues the MMSUPPORT structure with exactly this name. The structure survives but is named MMSUPPORT_FULL and combines new MMSUPPORT_INSTANCE and MMSUPPORT_SHARED structures which each have a different selection of the old MMSUPPORT members.

Variability

As an internal structure with little, if any, visibility outside the kernel, the MMSUPPORT varies greatly between versions and even between builds. In the following table of sizes, different builds of the same version are distinguished as early and late because they are known to vary the structure even if they don’t change the size. These descriptions, as early and late, are then used throughout the article as a shorthand.

Version Size (x86) Size (x64)
3.10 to 4.0 0x30  
5.0 0x48  
5.1 0x40  
early 5.2 (before SP1) 0x60  
late 5.2 (SP1 and higher) 0x48 0x58
early 6.0 (before SP1)
late 6.0 (SP1 and higher)
0x48 0x68
6.1 0x6C 0x88
6.2 0x70 0x90
6.3 0x70 0xD8
10.0 to 1511 0x80 0xF8

Layout

These sizes, and the names, offsets and types in the tables that follow, are from Microsoft’s symbol files for the kernel starting with Windows 2000 SP3.

Windows 7 and Higher

The MMSUPPORT varies enough between versions that it seems simpler to present its current form and then a separate history. Windows 7 is here taken as a convenient break. Much of the structure was reordered for Windows 7, both on a large scale and small. For instance, the first three members were at the very end of the structure when version 6.0 introduced them, but version 6.1 doesn’t move them as one block: it also swaps two of them. On the plus side for presentation, although there have since been insertions, deletions and changes of type (notably because support in 64-bit Windows 8.1 for more than 4G pages requires the widening of many members from 32 bits), those reorderings for Windows 7 were the last until the structure was split.

Offset (x86) Offset (x64) Definition Versions Remarks
0x00 0x00
EX_PUSH_LOCK WorkingSetMutex;
6.1 to 6.3 previously 0x40 and 0x58
LONG volatile WorkingSetLock;
10.0 to 1511 next at 0x00 in MMSUPPORT_SHARED
0x04 0x08
KGATE *ExitGate;
6.1 to 6.3 previously 0x3C and 0x50
KGATE *ExitOutswapGate;
10.0 to 1511 next at 0x34 and 0x60 in MMSUPPORT_INSTANCE
0x08 0x10
PVOID AccessLog;
6.1 to 1511 previously 0x44 and 0x60;
next at 0x14 and 0x28 in MMSUPPORT_SHARED
0x0C 0x18
LIST_ENTRY WorkingSetExpansionLinks;
6.1 to 1511 previously 0x00;
next at 0x10 and 0x18 in MMSUPPORT_INSTANCE
0x14 0x28
ULONG AgeDistribution [7];
6.1 to 6.2  
ULONG_PTR AgeDistribution [7];
6.3 to 1511 next at 0x18 and 0x28 in MMSUPPORT_INSTANCE
0x30 0x44 (6.1 to 6.2);
0x60
ULONG MinimumWorkingSetSize;
6.1 to 6.2 previously 0x1C and 0x24
ULONG_PTR MinimumWorkingSetSize;
6.3 to 1511 next at 0x38 and 0x68 in MMSUPPORT_INSTANCE
0x34 0x68
ULONG_PTR WorkingSetLeafSize;
10.0 to 1511 next at 0x3C and 0x70 in MMSUPPORT_INSTANCE
0x38 0x70
ULONG_PTR WorkingSetLeafPrivateSize;
10.0 to 1511 next at 0x40 and 0x78 in MMSUPPORT_INSTANCE
0x34 (6.1 to 6.3);
0x3C
0x48 (6.1 to 6.2);
0x68 (6.3);
0x78
ULONG WorkingSetSize;
6.1 to 6.2 previously 0x38 and 0x48
ULONG_PTR WorkingSetSize;
6.3 to 1511 next at 0x44 and 0x80 in MMSUPPORT_INSTANCE
0x38 (6.1 to 6.3);
0x40
0x4C (6.1 to 6.2);
0x70 (6.3);
0x80
ULONG WorkingSetPrivateSize;
6.1 to 6.2 previously 0x30 and 0x40
ULONG_PTR WorkingSetPrivateSize;
6.3 to 1511 next at 0x48 and 0x88 in MMSUPPORT_INSTANCE
0x3C (6.1 to 6.3);
0x44
0x50 (6.1 to 6.2);
0x78 (6.3);
0x88
ULONG MaximumWorkingSetSize;
6.1 to 6.2 previously 0x20 and 0x28
ULONG_PTR MaximumWorkingSetSize;
6.3 to 1511 next at 0x4C and 0x90 in MMSUPPORT_INSTANCE
0x40 (6.1 to 6.3);
0x48
0x54 (6.1 to 6.2);
0x80 (6.3);
0x90
ULONG ChargedWslePages;
6.1 to 6.2 previously 0x18 and 0x20
ULONG_PTR ChargedWslePages;
6.3 to 1511 next at 0x18 and 0x30 in MMSUPPORT_SHARED
0x44 (6.1 to 6.3);
0x4C
0x58 (6.1 to 6.2);
0x88 (6.3);
0x98
ULONG ActualWslePages;
6.1 to 6.2 previously 0x2C and 0x3C
ULONG_PTR ActualWslePages;
6.3 to 1511 next at 0x1C and 0x38 in MMSUPPORT_SHARED
0x48 (6.1 to 6.3);
0x50
0x5C (6.1 to 6.2);
0x90 (6.3);
0xA0
ULONG WorkingSetSizeOverhead;
6.1 to 6.2 previously 0x34 and 0x44
ULONG_PTR WorkingSetSizeOverhead;
6.3 to 1511 next at 0x20 and 0x40 in MMSUPPORT_SHARED
0x4C (6.1 to 6.3);
0x54
0x60 (6.1 to 6.2);
0x98 (6.3);
0xA8
ULONG PeakWorkingSetSize;
6.1 to 6.2 previously 0x14 and 0x1C
ULONG_PTR PeakWorkingSetSize;
6.3 to 1511 next at 0x50 and 0x98 in MMSUPPORT_INSTANCE
0x50 (6.1 to 6.3);
0x58
0x64 (6.1 to 6.2);
0xA0 (6.3);
0xB0
ULONG HardFaultCount;
6.1 to 1511 next at 0x54 and 0xA0 in MMSUPPORT_INSTANCE
  0xB4
USHORT PartitionId;
10.0 to 1511 next at 0xA4 in MMSUPPORT_INSTANCE
  0xB6
USHORT Pad0;
10.0 to 1511 next at 0xA6 in MMSUPPORT_INSTANCE
0x54 (6.1 to 6.3);
0x5C
0x68 (6.1 to 6.2);
0xA8 (6.3);
0xB8
MMWSL *VmWorkingSetList;
6.1 to 1511 previously 0x24 and 0x30;
next at 0x0C and 0x10 in MMSUPPORT_INSTANCE
0x58 (6.1 to 6.3);
0x60
0x70 (6.1 to 6.2);
0xB0 (6.3);
0xC0
USHORT NextPageColor;
6.1 to 1511 previously 0x0A and 0x12;
next at 0x00 in MMSUPPORT_INSTANCE
0x5A (6.1 to 6.3);
0x62
0x72 (6.1 to 6.2);
0xB2 (6.3);
0xC2
USHORT LastTrimStamp;
6.1 to 1511 previously 0x08 and 0x10;
next at 0x02 in MMSUPPORT_INSTANCE
0x5C (6.1 to 6.3);
0x64
0x74 (6.1 to 6.2);
0xB4 (6.3);
0xC4
ULONG PageFaultCount;
6.1 to 1511 previously 0x10 and 0x18;
next at 0x04 in MMSUPPORT_INSTANCE
0x60 (6.1) 0x78 (6.1)
ULONG RepurposeCount;
6.1 only  
0x60 (6.2 to 6.3);
0x68
0x78 (6.2);
0xB8 (6.3);
0xC8
ULONG TrimmedPageCount;
6.2 only  
ULONG_PTR TrimmedPageCount;
6.3 to 1511 next at 0x08 in MMSUPPORT_INSTANCE
0x64 (6.1) 0x7C (6.1 to 6.2)
ULONG Spare [1];
6.1 only (x86)  
ULONG Spare [2];
6.1 only (x64)  
ULONG Spare;
6.2 only (x64)  
0x64 (6.2 to 6.3);
0x6C
0x80 (6.2);
0xC0 (6.3);
0xD0
ULONG ForceTrimPages;
6.2 only  
ULONG_PTR ForceTrimPages;
6.3 to 1511  
0x68 (6.1 to 6.3);
0x70
0x84 (6.1 to 6.2);
0xC8 (6.3);
0xD8
MMSUPPORT_FLAGS Flags;
6.1 to 1511 previously 0x0C and 0x14;
next at 0x60 and 0xB8 in MMSUPPORT_INSTANCE;
last member in 6.1
0x74 0xE0
ULONG_PTR ReleasedCommitDebt;
10.0 to 1511 next at 0x04 and 0x08 in MMSUPPORT_SHARED
0x6C (6.2 to 6.3);
0x78
0x88 (6.2);
0xD0 (6.3);
0xE8
PVOID WsSwapSupport;
6.2 to 1511 next at 0x0C and 0x18 in MMSUPPORT_SHARED;
last member in 6.2 and 6.3
0x7C 0xF0
PVOID CommitReAcquireFailSupport;
10.0 to 1511 last member in 10.0 and 1511

Original

Very many of the members have an earlier history, often all the way back to version 3.10, but with such extensive reordering for version 6.1 that separate presentation is all but necessary. Versions 5.1 and 5.2 reorder MMSUPPORT members too, so that the following table necessarily lists some members twice.

For versions that predate the availability of type information in public symbol files, what’s known of Microsoft’s names and types is something of a guess. Where use of a member corresponds closely with that of a version for which Microsoft’s symbols are available, it seems reasonable to suppose continuity. Some use, however, has no correspondence, the code having changed too much. Even where the use hasn’t changed, tracking it down exhaustively would be difficult, if not impossible, even with source code.

Offset (x86) Offset (x64) Definition Versions Remarks
0x00 (5.2 to 6.0)
0x00 (5.2 to 6.0)
LIST_ENTRY WorkingSetExpansionLinks;
5.2 to 6.0 previously 0x24
0x00 (3.10 to 5.1);
0x08 (5.2)
0x10 (5.2)
LARGE_INTEGER LastTrimTime;
3.10 to 5.2  
0x08 (3.10 to 5.0)  
ULONG LastTrimFaultCount;
3.10 to 5.0  
0x08 (6.0) 0x10 (6.0)
USHORT LastTrimStamp;
6.0 next at 0x5A and 0x72
0x0A (6.0) 0x12 (6.0)
USHORT NextPageColor;
6.0 next at 0x58 and 0x70
0x08 (5.1);
0x10 (5.2);
0x0C (6.0)
0x18 (5.2);
0x14 (6.0)
MMSUPPORT_FLAGS Flags;
5.1 to 6.0 previously 0x30;
next at 0x68 and 0x84
0x0C (3.10 to 5.1);
0x14 (5.2);
0x10 (6.0)
0x1C (5.2);
0x18 (6.0)
ULONG PageFaultCount;
3.10 to 6.0 next at 0x5C and 0x74
0x10 (3.10 to 5.1);
0x18 (5.2);
0x14 (6.0)
0x20 (5.2);
0x1C (6.0)
ULONG PeakWorkingSetSize;
3.10 to 6.0 next at 0x4C and 0x60
0x14 (3.10 to 5.1)  
ULONG WorkingSetSize;
3.10 to 5.1 next at 0x3C
0x1C (5.2) 0x24 (5.2)
ULONG GrowthSinceLastEstimate;
5.2 only previously 0x3C
0x18 (6.0) 0x20 (6.0)
ULONG Spare0;
early 6.0  
ULONG ChargedWslePages;
late 6.0 next at 0x40 and 0x54
0x18 (3.10 to 5.1);
0x20 (5.2);
0x1C (6.0)
0x28 (5.2);
0x24 (6.0)
ULONG MinimumWorkingSetSize;
3.10 only  
USHORT MinimumWorkingSetSize;
3.50 only  
ULONG MinimumWorkingSetSize;
3.51 to 6.0 next at 0x30 and 0x44
0x1C (3.10);
0x1A (3.50);
0x1C (3.51 to 5.1);
0x24 (5.2);
0x20 (6.0)
0x2C (5.2);
0x28 (6.0)
ULONG MaximumWorkingSetSize;
3.10 only  
USHORT MaximumWorkingSetSize;
3.50 only  
ULONG MaximumWorkingSetSize;
3.51 to 6.0 next at 0x3C and 0x50

For the several members whose names tell of a size, the size is a count of pages. All are 32-bit counts, except that version 3.50 reduces the MinimumWorkingSetSize and MaximumWorkingSetSize to allow only 16 bits (but still counting pages). The reason is not known. The immediately adjacent change is the squeezing in of the VmWorkingSetList (next). This has the the merit of making no other rearrangement, but since the structure had otherwise unused alignment space at offset 0x2C, the new member could have been added without any rearrangement at all. More archaeology is required!

Offset (x86) Offset (x64) Definition Versions Remarks
0x1C (3.50);
0x20 (3.51 to 5.1);
0x28 (5.2);
0x24 (6.0)
0x30 (5.2 to 6.0)
MMWSL *VmWorkingSetList;
3.50 to 6.0 next at 0x54 and 0x68
0x20 (3.10 to 3.50);
0x24 (3.51 to 5.1)
 
LIST_ENTRY WorkingSetExpansionLinks;
3.10 to 5.1 next at 0x00
0x28 (3.10 to 3.50);
0x2C (3.51 to 5.0)
 
UCHAR AllowWorkingSetAdjustment;
3.10 to 5.0 next in Flags
0x29 (3.10 to 3.50);
0x2D (3.51 to 5.0)
 
BOOLEAN AddressSpaceBeingDeleted;
3.10 to 5.0 next in Flags
0x2A (3.10 to 3.50);
0x2E (3.51 to 5.0)
 
UCHAR ForegroundSwitchCount;
3.10 to 5.0 last member in 3.10
0x2B (3.50);
0x2F (3.51 to 5.0)
 
UCHAR MemoryPriority;
3.50 to 5.0 next in Flags;
last member in 3.50 to 4.0
0x30 (5.0)  
union {
    ULONG LongFlags;
    MMSUPPORT_FLAGS Flags;
} u;
5.0 only next at 0x08 and 0x18
0x34 (5.0);
0x2C (5.1 to 5.2);
0x28 (6.0)
0x38 (5.2 to 6.0)
ULONG Claim;
5.0 to 6.0  
0x2C (6.0) 0x3C (6.0)
ULONG Spare [1];
early 6.0  
ULONG ActualWslePages;
late 6.0 next at 0x44 and 0x58
0x38 (5.0);
0x30 (5.1 to 5.2)
0x3C (5.2)
ULONG NextEstimationSlot;
5.0 to 5.2  
0x3C (5.0);
0x34 (5.1 to 5.2)
0x40 (5.2)
ULONG NextAgingSlot;
5.0 to 5.2  
0x40 (5.0);
0x38 (5.1 to 5.2)
0x44 (5.2)
ULONG EstimatedAvailable;
5.0 to 5.2  
0x44 (5.0);
0x3C (5.1)
 
ULONG GrowthSinceLastEstimate;
5.0 to 5.1 next at 0x1C;
last member in 5.0 and 5.1
0x30 (6.0) 0x40 (6.0)
ULONG WorkingSetPrivateSize;
6.0 only next at 0x38 and 0x4C
0x34 (6.0) 0x44 (6.0)
ULONG WorkingSetSizeOverhead;
6.0 only next at 0x48 and 0x5C
0x3C (5.2);
0x38 (6.0)
0x48 (5.2 to 6.0)
ULONG WorkingSetSize;
5.2 to 6.0 previously 0x14;
next at 0x34 and 0x48
0x3C (6.0) 0x50 (6.0)
KEVENT *ExitEvent;
early 6.0  
KGATE *ExitGate;
late 6.0 next at 0x04 and 0x08
0x40 (5.2 to 6.0)  
KGUARDED_MUTEX WorkingSetMutex;
early 5.2 last member in early 5.2
0x50 (5.2);
0x58 (6.0)
EX_PUSH_LOCK WorkingSetMutex;
late 5.2 to 6.0 next at 0x00;
last member in late 5.2
0x44 (6.0) 0x60 (6.0)
PVOID AccessLog;
6.0 only next at 0x08 and 0x10;
last member in 6.0