JIURL玩玩Win2k内存篇 LookasideList

来源:互联网 发布:linux命令学习手册 编辑:程序博客网 时间:2024/05/21 12:45
系统的堆的简介

    系统的堆是系统的数据动态申请和释放的地方。Win2k 把系统堆叫做 pool。根据是否可以被换出物理内存,分为 PagedPool 和 NonPagedPool。

LookasideList

    Windows 2000 中有很多种结构,这些结构需要动态申请。也就是在系统的 pool 中申请。在 pool 中申请和释放内存都是比较慢的,因为申请的时候需要在 pool 中寻找合适大小的空闲块,释放的时候还要考虑合并空闲块,等等繁琐的操作。系统中有很多很多的固定大小的结构需要动态分配,为了提高效率,系统使用了 LookasideList 。

    Windows 2000 中有很多的 LookasideList 。某种 LookasideList 申请固定大小的存。LookasideList 从 Paged pool 或者 Nonpaged pool 中申请内存。对于 LookasideList 上的块释放的时候,它并不是被直接释放到 pool 中,而有可能放在 LookasideList 上,这样如果再有申请的话,就不用再去 pool 中查找合适大小的空闲块,而可以直接取走使用了。也就是申请的时候,仍然是去 pool 中申请一块一定大小的内存。但是释放的时候,很有可能并不释放回堆里去,而是被 LookasideList 保留下来,供再申请的时候使用。后面我们将会发现系统中 LookasideList 的数量很多,如果申请过的块都不被释放的话,那不是要白白占用很多内存,有可能导致别人的新的申请申请不到内存?不必担心,每个 LookasideList 最多只保留很少的几块,如果超过,就会释放回 pool 里去。系统也会定时检查。

    Windows 2000 把很多 LookasideList 链在两个链上。根据该 LookasideList 是从 Paged pool 还是从 Nonpaged pool 中申请内存。从 Paged pool 中申请内存的 LookasideList 链在 PagedLookasideList 上。从 Nonpaged pool 中申请内存的 LookasideList 链在 NPagedLookasideList 上。

在 ntddk.h 中有两种 LookasideList (NPAGED_LOOKASIDE_LIST 和 PAGED_LOOKASIDE_LIST) 及其相关结构的定义。通过 kd 也可以得到他们的结构定义。

typedef struct _NPAGED_LOOKASIDE_LIST {GENERAL_LOOKASIDE L;KSPIN_LOCK Lock;} NPAGED_LOOKASIDE_LIST, *PNPAGED_LOOKASIDE_LIST;typedef struct _PAGED_LOOKASIDE_LIST {GENERAL_LOOKASIDE L;FAST_MUTEX Lock;} PAGED_LOOKASIDE_LIST, *PPAGED_LOOKASIDE_LIST;

kd> !strct GENERAL_LOOKASIDE!strct GENERAL_LOOKASIDEstruct _GENERAL_LOOKASIDE (sizeof=72)+00 union _SLIST_HEADER ListHead+00 uint64 Alignment+00 struct _SINGLE_LIST_ENTRY Next+00 struct _SINGLE_LIST_ENTRY *Next+04 uint16 Depth+06 uint16 Sequence+08 uint16 Depth+0a uint16 MaximumDepth+0c uint32 TotalAllocates+10 uint32 AllocateMisses+10 uint32 AllocateHits+14 uint32 TotalFrees+18 uint32 FreeMisses+18 uint32 FreeHits+1c int32 Type// 表明是 NPAGED 还是 PAGED。 为0表示NPAGED 。为1表示PAGED。+20 uint32 Tag// 4个字节,通常放入4个字母来作为标记。比如 ObpCreateInfoLookasideList 使用 "ObCi"。+24 uint32 Size// 这个 LookasideList 上每项的大小。+28 function *Allocate// 申请函数,通常放 ExAllocatePoolWithTag+2c function *Free// 释放函数,通常放 ExFreePool+30 struct _LIST_ENTRY ListEntry+30 struct _LIST_ENTRY *Flink+34 struct _LIST_ENTRY *Blink// 这里把同一种类型(NPAGED 或者 PAGED)的 LookasideList 链在一起。+38 uint32 LastTotalAllocates+3c uint32 LastAllocateMisses+3c uint32 LastAllocateHits+40 uint32 Future[2]

typedef struct _SINGLE_LIST_ENTRY {struct _SINGLE_LIST_ENTRY *Next;} SINGLE_LIST_ENTRY, *PSINGLE_LIST_ENTRY;

下面我们使用 kd 分别遍历这两个链表

遍历 PagedLookasideListkd> ? ExPagedLookasideListHead? ExPagedLookasideListHeadEvaluate expression: -2142817432 = 80473368// 全局变量 ExPagedLookasideListHead kd> !strct LIST_ENTRY ExPagedLookasideListHead!strct LIST_ENTRY ExPagedLookasideListHeadstruct _LIST_ENTRY (sizeof=8)+0 struct _LIST_ENTRY *Flink = 8046A9D0+4 struct _LIST_ENTRY *Blink = 810EAF38// PagedLookasideList 链上的 PAGED_LOOKASIDE_LIST 结构中的 LIST_ENTRY ListEntry!strct PAGED_LOOKASIDE_LISTstruct _PAGED_LOOKASIDE_LIST (sizeof=104)...+30 struct _LIST_ENTRY ListEntry...kd> ? 8046A9D0-30? 8046A9D0-30Evaluate expression: -2142852704 = 8046a9a0// 验证一下kd> !lookaside 8046a9a0!lookaside 8046a9a0Lookaside "" @ 8046a9a0 "TunL"Type = 0001 PagedPoolCurrent Depth = 1 Max Depth = 4Size = 136 Max Alloc = 544AllocateMisses = 293 FreeMisses = 283TotalAllocates = 478 TotalFrees = 469Hit Rate = 38% Hit Rate = 39%

kd> !strct PAGED_LOOKASIDE_LIST 8046a9a0!strct PAGED_LOOKASIDE_LIST 8046a9a0struct _PAGED_LOOKASIDE_LIST (sizeof=104)+00 struct _GENERAL_LOOKASIDE L+00 union _SLIST_HEADER ListHead+00 uint64 Alignment = 01730001e35116c8+00 struct _SINGLE_LIST_ENTRY Next+00 struct _SINGLE_LIST_ENTRY *Next = E35116C8+04 uint16 Depth = 0001+06 uint16 Sequence = 0173+08 uint16 Depth = 0004+0a uint16 MaximumDepth = 0100+0c uint32 TotalAllocates = 000001de+10 uint32 AllocateMisses = 00000125+10 uint32 AllocateHits = 00000125+14 uint32 TotalFrees = 000001d5+18 uint32 FreeMisses = 0000011b+18 uint32 FreeHits = 0000011b+1c int32 Type = 00000001 // 1=PagedPool+20 uint32 Tag = 4c6e7554+24 uint32 Size = 00000088 // 0x88=136+28 function *Allocate = 80466C80+2c function *Free = 80467297+30 struct _LIST_ENTRY ListEntry+30 struct _LIST_ENTRY *Flink = 804734B0+34 struct _LIST_ENTRY *Blink = 80473368+38 uint32 LastTotalAllocates = 000001dd+3c uint32 LastAllocateMisses = 00000125+3c uint32 LastAllocateHits = 00000125+40 uint32 Future[2] = 00000000 00000000 .... ....+48 struct _FAST_MUTEX Lock+48 int32 Count = 00000001+4c struct _KTHREAD *Owner = 00000000+50 uint32 Contention = 00000000+54 struct _KEVENT Event+54 struct _DISPATCHER_HEADER Header+54 byte Type = 01 .+55 byte Absolute = 00 .+56 byte Size = 04 .+57 byte Inserted = 00 .+58 int32 SignalState = 00000000+5c struct _LIST_ENTRY WaitListHead+5c struct _LIST_ENTRY *Flink = 8046A9FC //+60 struct _LIST_ENTRY *Blink = 8046A9FC+64 uint32 OldIrql = 00000000

kd> dd ExPagedLookasideListHead l 2dd ExPagedLookasideListHead l 280473368 8046a9d0 810eaf38// 记住我们是从 ExPagedLookasideListHead 80473368 开始的,当我们再看到 80473368// 就表示链已经循环了。kd> dd $p l 2dd $p l 28046a9d0 804734b0 80473368kd>804734b0 80473730 8046a9d0kd>80473730 804802f0 804734b0kd>804802f0 80480a90 80473730kd>80480a90 fcccd4b0 804802f0kd>fcccd4b0 fcccd590 80480a90kd>fcccd590 810eba38 fcccd4b0kd>810eba38 810eb918 fcccd590kd>810eb918 810eb898 810eba38kd>810eb898 810eb818 810eb918kd>810eb818 810eb798 810eb898kd>810eb798 810eb718 810eb818kd>810eb718 810eb698 810eb798kd>810eb698 810ea038 810eb718kd>810ea038 810eafb8 810eb698kd>810eafb8 810eaf38 810ea038kd>810eaf38 80473368 810eafb8kd>80473368 8046a9d0 810eaf38// 我们又看到了 80473368 ,表示链已经循环了

遍历 NPagedLookasideList

kd> ? ExNPagedLookasideListHead? ExNPagedLookasideListHeadEvaluate expression: -2142817416 = 80473378kd> !strct LIST_ENTRY ExNPagedLookasideListHead!strct LIST_ENTRY ExNPagedLookasideListHeadstruct _LIST_ENTRY (sizeof=8)+0 struct _LIST_ENTRY *Flink = 8047F8D0+4 struct _LIST_ENTRY *Blink = EEFFEC90kd> !strct NPAGED_LOOKASIDE_LIST!strct NPAGED_LOOKASIDE_LISTstruct _NPAGED_LOOKASIDE_LIST (sizeof=80)...+30 struct _LIST_ENTRY ListEntry...kd> ? 8047F8D0-30? 8047F8D0-30Evaluate expression: -2142766944 = 8047f8a0kd> !lookaside 8047f8a0!lookaside 8047f8a0Lookaside "" @ 8047f8a0 "ObCi"Type = 0000 NonPagedPoolCurrent Depth = 2 Max Depth = 4Size = 48 Max Alloc = 192AllocateMisses = 24 FreeMisses = 0TotalAllocates = 73 TotalFrees = 51Hit Rate = 67% Hit Rate = 100%kd> !strct NPAGED_LOOKASIDE_LIST 8047f8a0!strct NPAGED_LOOKASIDE_LIST 8047f8a0struct _NPAGED_LOOKASIDE_LIST (sizeof=80)+00 struct _GENERAL_LOOKASIDE L+00 union _SLIST_HEADER ListHead+00 uint64 Alignment = 0064000281feeb88+00 struct _SINGLE_LIST_ENTRY Next+00 struct _SINGLE_LIST_ENTRY *Next = 81FEEB88+04 uint16 Depth = 0002+06 uint16 Sequence = 0064+08 uint16 Depth = 0004+0a uint16 MaximumDepth = 0100+0c uint32 TotalAllocates = 00000049+10 uint32 AllocateMisses = 00000018+10 uint32 AllocateHits = 00000018+14 uint32 TotalFrees = 00000033+18 uint32 FreeMisses = 00000000+18 uint32 FreeHits = 00000000+1c int32 Type = 00000000+20 uint32 Tag = 6943624f+24 uint32 Size = 00000030+28 function *Allocate = 80466C80+2c function *Free = 80467297+30 struct _LIST_ENTRY ListEntry+30 struct _LIST_ENTRY *Flink = 8047F930+34 struct _LIST_ENTRY *Blink = 80473378+38 uint32 LastTotalAllocates = 00000049+3c uint32 LastAllocateMisses = 00000018+3c uint32 LastAllocateHits = 00000018+40 uint32 Future[2] = 00000000 00000000 .... ....+48 uint32 Lock = 00000000

kd> dd ExNPagedLookasideListHead l 2dd ExNPagedLookasideListHead l 280473378 8047f8d0 eeffec90// 记住我们是从 ExPagedLookasideListHead 80473378 开始的,当我们再看到 80473378// 就表示链已经循环了。

kd> dd $p l 2dd $p l 28047f8d0 8047f930 80473378kd>8047f930 814521f8 8047f8d0kd>814521f8 81452198 8047f930kd>81452198 80472130 814521f8kd>80472130 8141b1b8 81452198kd>8141b1b8 80473650 80472130kd>80473650 804736b0 8141b1b8kd>804736b0 80473530 80473650kd>80473530 80473590 804736b0kd>80473590 804735f0 80473530kd>804735f0 804737b0 80473590kd>804737b0 80475830 804735f0kd>80475830 804756d0 804737b0kd>804756d0 804758d0 80475830kd>804758d0 80475770 804756d0kd>80475770 8141a2f8 804758d0kd>8141a2f8 81416d18 80475770kd>81416d18 81416cb8 8141a2f8kd>81416cb8 81416c58 81416d18kd>81416c58 80480b30 81416cb8kd>80480b30 fcd5c510 81416c58kd>fcd5c510 fcd5c1b0 80480b30kd>fcd5c1b0 fcd5c390 fcd5c510kd>fcd5c390 fcd5c290 fcd5c1b0kd>fcd5c290 fcd5c0f0 fcd5c390kd>fcd5c0f0 fcd1e9b0 fcd5c290kd>fcd1e9b0 fcd1ea00 fcd5c0f0kd>fcd1ea00 813d0618 fcd1e9b0kd>813d0618 813cf3d8 fcd1ea00kd>813cf3d8 813f6ef8 813d0618kd>813f6ef8 813f6c58 813cf3d8kd>813f6c58 8140c198 813f6ef8kd>8140c198 8140cef8 813f6c58kd>8140cef8 8140cc58 8140c198kd>8140cc58 8140c9b8 8140cef8kd>8140c9b8 8140c6b8 8140cc58kd>8140c6b8 813f5198 8140c9b8kd>813f5198 813f53d8 8140c6b8kd>813f53d8 fcccd430 813f5198kd>fcccd430 fcccd530 813f53d8kd>fcccd530 fcccd610 fcccd430kd>fcccd610 813c84b8 fcccd530kd>813c84b8 f08915d0 fcccd610kd>f08915d0 f0325c10 813c84b8kd>f0325c10 f0325a30 f08915d0kd>f0325a30 f0325ff0 f0325c10kd>f0325ff0 f0325a90 f0325a30kd>f0325a90 f0325f70 f0325ff0kd>f0325f70 f03260f0 f0325a90kd>f03260f0 f03259d0 f0325f70kd>f03259d0 8132eb58 f03260f0kd>8132eb58 812aa5f0 f03259d0kd>812aa5f0 812aa640 8132eb58kd>812aa640 812aa690 812aa5f0kd>812aa690 812aa6e0 812aa640kd>812aa6e0 812aa730 812aa690kd>812aa730 812aa780 812aa6e0kd>812aa780 f05283f0 812aa730kd>f05283f0 f0528450 812aa780kd>f0528450 812a7f98 f05283f0kd>812a7f98 812a32e8 f0528450kd>812a32e8 812a3338 812a7f98kd>812a3338 812a50f8 812a32e8kd>812a50f8 f05574b0 812a3338kd>f05574b0 f05572f0 812a50f8kd>f05572f0 f05576b0 f05574b0kd>f05576b0 f05573b0 f05572f0kd>f05573b0 f0557450 f05576b0kd>f0557450 f0557650 f05573b0kd>f0557650 f07fd150 f0557450kd>f07fd150 f07fd330 f0557650kd>f07fd330 ef093848 f07fd150kd>ef093848 ef05d910 f07fd330kd>ef05d910 810a6b38 ef093848kd>810a6b38 810a6b88 ef05d910kd>810a6b88 810a6bd8 810a6b38kd>810a6bd8 810a6c28 810a6b88kd>810a6c28 eeffeb50 810a6bd8kd>eeffeb50 eeffebf0 810a6c28kd>eeffebf0 eeffeba0 eeffeb50kd>eeffeba0 eeffec40 eeffebf0kd>eeffec40 eeffec90 eeffeba0kd>eeffec90 80473378 eeffec40kd>80473378 8047f8d0 eeffec90// 我们又看到了 80473378 ,表示链已经循环了

LookasideList 的项

    LookasideList 的项通过 +00 struct _SINGLE_LIST_ENTRY *Next 的链,链在一起。为空表示链结束。下面使用 kd 举一个例子。

kd> !lookaside 810eae68!lookaside 810eae68Lookaside "" @ 810eae68 "Usqm"Type = 0021 PagedPoolCurrent Depth = 4 Max Depth = 4Size = 48 Max Alloc = 192AllocateMisses = 922 FreeMisses = 918TotalAllocates = 56869 TotalFrees = 56869Hit Rate = 98% Hit Rate = 98%// 810eae68 处是 PAGED_LOOKASIDE_LIST +0 处的4个字节就是链的开始kd> dd 810eae68+0 l 1dd 810eae68+0 l 1810eae68 e2f44428// e2f44428 是指向Buf的指针,之前的4个字节是维护该Buf结构中的Tag// Buf的首地址开始的4个字节用来形成链kd> db e2f44428-4 l 4 ; dd e2f44428 l 1db e2f44428-4 l 4 ; dd e2f44428 l 1e2f44424 55 73 71 6d Usqme2f44428 e2fdc2a8kd> db e2fdc2a8-4 l 4 ; dd e2fdc2a8 l 1db e2fdc2a8-4 l 4 ; dd e2fdc2a8 l 1e2fdc2a4 55 73 71 6d Usqme2fdc2a8 e13a2c68kd> db e13a2c68-4 l 4 ; dd e13a2c68 l 1db e13a2c68-4 l 4 ; dd e13a2c68 l 1e13a2c64 55 73 71 6d Usqme13a2c68 e16d4f88kd> db e16d4f88-4 l 4 ; dd e16d4f88 l 1db e16d4f88-4 l 4 ; dd e16d4f88 l 1e16d4f84 55 73 71 6d Usqme16d4f88 00000000// 我们看到每一个的Tag的确是 Usqm。也看到一共4项,和通过 PAGED_LOOKASIDE_LIST 结构得到的项数是相// 符的。最后一项为0表示链表结束。

LookasideList 上的申请与释放

    跟 ntoskrnl!ExFreeToPagedLookasideList 会发现,会比较 LookasideList 结构+4处的 ListHead.Depth(uint16)和+8处的Depth(uint16),如果 ListHead.Depth 小于 Depth 就会把被free的项插入到链头(将free项的开始4个字节,设为原来的链头,然后把链头的值设为free项的地址)如果大于等于的话,就会用free项地址做参数调用+2c处的free函数。

    跟 ntoskrnl!ExAllocateFromPagedLookasideList 会发现,会测试 LookasideList 结构开头的Next是否为空,为空调用+28处的alloc函数申请一块。不为空就把这一块提交。

原创粉丝点击