Geoff Chappell - Software Analyst
The PP_LOOKASIDE_LIST structure (formally _PP_LOOKASIDE_LIST) is a container for two lookaside lists treated as one per-processor lookaside list.
The kernel has long provided lookaside lists for efficient management of memory for the sort of fixed-size structures that the kernel itself and many kernel-mode drivers find themselves allocating and freeing over and over. Instead of freeing the memory all the way back to where it was first obtained, e.g., non-paged pool, the memory is ideally retained in an immediately accessible list. Some such structures see such heavy use that starting with Windows 2000 the kernel keeps a list for each processor.
Each PP_LOOKASIDE_LIST is a pair of pointers, the first to a lookaside list that is specific to that processor, the second to one that is shared among all processors (like any other). For each type of fixed-size structure that is managed through this per-processor lookaisde list, allocations are sought first from the per-processor list, for speed, else from the shared list. Allocations are freed to the per-processor list for easy re-allocation, except that if the list has reached its capacity the allocation is instead freed to the shared list.
In version 5.0 and higher, the KPRCB for each processor has an array named PPLookasideList of 0x10 PP_LOOKASIDE_LIST structures. The PP_NPAGED_LOOKASIDE_NUMBER enumeration indexes this array. Each value of the enumeration corresponds to a different fixed-size structure whose memory is managed through the corresponding per-processor lookaside list.
In versions 5.0 to 5.2, the KPRCB also has arrays named PPNPagedLookasideList and PPPagedLookasideList. These also are arrays of PP_LOOKASIDE_LIST structures, but these per-processor lookaside lists do not each manage memory for a particular fixed-size structure that is frequently allocated and freed. Instead, they are an efficiency for allocating and freeing small pool blocks for general use. The two arrays are for small allocations from non-paged and pages pool, respectively. Successive per-processor lookaside lists in each array are for successively larger pool blocks. Version 5.0 provides for eight lists, with a first list for pool blocks up to and including 0x20 bytes, and a last list for pool blocks up to and including 0x0100 bytes. Versions 5.1 and 5.2 cover the same range but with 32 lists. That kernel-mode programmers can reasonably think of small pool allocations as having no significant overhead is mostly due to this management through per-processor lookaside lists. So frequent are small pool allocations that there’s arguably little to gain from ever putting a freed block onto a shared list: it will soon enough be needed for the same processor. Version 6.0 did away with this fallback. Successive sizes of pool block each need only one lookaside list. The PP_LOOKASIDE_LIST with its pointers to two lists is redundant and the arrays are instead of GENERAL_LOOKASIDE_POOL structures.
The PP_LOOKASIDE_LIST structure is not documented. Microsoft has published a C-language definition in the NTOSP.H from the Windows Driver Kit (WDK) for Windows 10 in the original and Version 1511 editions only.
The PP_LOOKASIDE_LIST is 0x08 or 0x10 bytes in 32-bit and 64-bit Windows, respectively. Its name and size, and the offsets, names and types of its members are known from public symbol files for the kernel starting with Windows 2000 SP3.
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x00 | 0x00 |
NPAGED_LOOKASIDE_LIST *P; |
5.0 only |
GENERAL_LOOKASIDE *P; |
5.1 and higher | ||
0x04 | 0x08 |
NPAGED_LOOKASIDE_LIST *L; |
5.0 only |
GENERAL_LOOKASIDE *L; |
5.1 and higher |