阅读:1078回复:2
JIURL玩玩Win2k内存篇 LookasideList
JIURL玩玩Win2k内存篇 LookasideList
作者: JIURL 主页: http://jiurl.yeah.net 日期: 2003-7-30 -------------------------------------------------------------------------------- 系统的堆的简介 系统的堆是系统的数据动态申请和释放的地方。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_LOOKASIDE struct _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 分别遍历这两个链表 遍历 PagedLookasideList kd> ? ExPagedLookasideListHead ? ExPagedLookasideListHead Evaluate expression: -2142817432 = 80473368 // 全局变量 ExPagedLookasideListHead kd> !strct LIST_ENTRY ExPagedLookasideListHead !strct LIST_ENTRY ExPagedLookasideListHead struct _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_LIST struct _PAGED_LOOKASIDE_LIST (sizeof=104) ... +30 struct _LIST_ENTRY ListEntry ... kd> ? 8046A9D0-30 ? 8046A9D0-30 Evaluate expression: -2142852704 = 8046a9a0 // 验证一下 kd> !lookaside 8046a9a0 !lookaside 8046a9a0 Lookaside \"\" @ 8046a9a0 \"TunL\" Type = 0001 PagedPool Current Depth = 1 Max Depth = 4 Size = 136 Max Alloc = 544 AllocateMisses = 293 FreeMisses = 283 TotalAllocates = 478 TotalFrees = 469 Hit Rate = 38% Hit Rate = 39% kd> !strct PAGED_LOOKASIDE_LIST 8046a9a0 !strct PAGED_LOOKASIDE_LIST 8046a9a0 struct _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 2 dd ExPagedLookasideListHead l 2 80473368 8046a9d0 810eaf38 // 记住我们是从 ExPagedLookasideListHead 80473368 开始的,当我们再看到 80473368 // 就表示链已经循环了。 kd> dd $p l 2 dd $p l 2 8046a9d0 804734b0 80473368 kd> 804734b0 80473730 8046a9d0 kd> 80473730 804802f0 804734b0 kd> 804802f0 80480a90 80473730 kd> 80480a90 fcccd4b0 804802f0 kd> fcccd4b0 fcccd590 80480a90 kd> fcccd590 810eba38 fcccd4b0 kd> 810eba38 810eb918 fcccd590 kd> 810eb918 810eb898 810eba38 kd> 810eb898 810eb818 810eb918 kd> 810eb818 810eb798 810eb898 kd> 810eb798 810eb718 810eb818 kd> 810eb718 810eb698 810eb798 kd> 810eb698 810ea038 810eb718 kd> 810ea038 810eafb8 810eb698 kd> 810eafb8 810eaf38 810ea038 kd> 810eaf38 80473368 810eafb8 kd> 80473368 8046a9d0 810eaf38 // 我们又看到了 80473368 ,表示链已经循环了 遍历 NPagedLookasideList kd> ? ExNPagedLookasideListHead ? ExNPagedLookasideListHead Evaluate expression: -2142817416 = 80473378 kd> !strct LIST_ENTRY ExNPagedLookasideListHead !strct LIST_ENTRY ExNPagedLookasideListHead struct _LIST_ENTRY (sizeof=8) +0 struct _LIST_ENTRY *Flink = 8047F8D0 +4 struct _LIST_ENTRY *Blink = EEFFEC90 kd> !strct NPAGED_LOOKASIDE_LIST !strct NPAGED_LOOKASIDE_LIST struct _NPAGED_LOOKASIDE_LIST (sizeof=80) ... +30 struct _LIST_ENTRY ListEntry ... kd> ? 8047F8D0-30 ? 8047F8D0-30 Evaluate expression: -2142766944 = 8047f8a0 kd> !lookaside 8047f8a0 !lookaside 8047f8a0 Lookaside \"\" @ 8047f8a0 \"ObCi\" Type = 0000 NonPagedPool Current Depth = 2 Max Depth = 4 Size = 48 Max Alloc = 192 AllocateMisses = 24 FreeMisses = 0 TotalAllocates = 73 TotalFrees = 51 Hit Rate = 67% Hit Rate = 100% kd> !strct NPAGED_LOOKASIDE_LIST 8047f8a0 !strct NPAGED_LOOKASIDE_LIST 8047f8a0 struct _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 2 dd ExNPagedLookasideListHead l 2 80473378 8047f8d0 eeffec90 // 记住我们是从 ExPagedLookasideListHead 80473378 开始的,当我们再看到 80473378 // 就表示链已经循环了。 kd> dd $p l 2 dd $p l 2 8047f8d0 8047f930 80473378 kd> 8047f930 814521f8 8047f8d0 kd> 814521f8 81452198 8047f930 kd> 81452198 80472130 814521f8 kd> 80472130 8141b1b8 81452198 kd> 8141b1b8 80473650 80472130 kd> 80473650 804736b0 8141b1b8 kd> 804736b0 80473530 80473650 kd> 80473530 80473590 804736b0 kd> 80473590 804735f0 80473530 kd> 804735f0 804737b0 80473590 kd> 804737b0 80475830 804735f0 kd> 80475830 804756d0 804737b0 kd> 804756d0 804758d0 80475830 kd> 804758d0 80475770 804756d0 kd> 80475770 8141a2f8 804758d0 kd> 8141a2f8 81416d18 80475770 kd> 81416d18 81416cb8 8141a2f8 kd> 81416cb8 81416c58 81416d18 kd> 81416c58 80480b30 81416cb8 kd> 80480b30 fcd5c510 81416c58 kd> fcd5c510 fcd5c1b0 80480b30 kd> fcd5c1b0 fcd5c390 fcd5c510 kd> fcd5c390 fcd5c290 fcd5c1b0 kd> fcd5c290 fcd5c0f0 fcd5c390 kd> fcd5c0f0 fcd1e9b0 fcd5c290 kd> fcd1e9b0 fcd1ea00 fcd5c0f0 kd> fcd1ea00 813d0618 fcd1e9b0 kd> 813d0618 813cf3d8 fcd1ea00 kd> 813cf3d8 813f6ef8 813d0618 kd> 813f6ef8 813f6c58 813cf3d8 kd> 813f6c58 8140c198 813f6ef8 kd> 8140c198 8140cef8 813f6c58 kd> 8140cef8 8140cc58 8140c198 kd> 8140cc58 8140c9b8 8140cef8 kd> 8140c9b8 8140c6b8 8140cc58 kd> 8140c6b8 813f5198 8140c9b8 kd> 813f5198 813f53d8 8140c6b8 kd> 813f53d8 fcccd430 813f5198 kd> fcccd430 fcccd530 813f53d8 kd> fcccd530 fcccd610 fcccd430 kd> fcccd610 813c84b8 fcccd530 kd> 813c84b8 f08915d0 fcccd610 kd> f08915d0 f0325c10 813c84b8 kd> f0325c10 f0325a30 f08915d0 kd> f0325a30 f0325ff0 f0325c10 kd> f0325ff0 f0325a90 f0325a30 kd> f0325a90 f0325f70 f0325ff0 kd> f0325f70 f03260f0 f0325a90 kd> f03260f0 f03259d0 f0325f70 kd> f03259d0 8132eb58 f03260f0 kd> 8132eb58 812aa5f0 f03259d0 kd> 812aa5f0 812aa640 8132eb58 kd> 812aa640 812aa690 812aa5f0 kd> 812aa690 812aa6e0 812aa640 kd> 812aa6e0 812aa730 812aa690 kd> 812aa730 812aa780 812aa6e0 kd> 812aa780 f05283f0 812aa730 kd> f05283f0 f0528450 812aa780 kd> f0528450 812a7f98 f05283f0 kd> 812a7f98 812a32e8 f0528450 kd> 812a32e8 812a3338 812a7f98 kd> 812a3338 812a50f8 812a32e8 kd> 812a50f8 f05574b0 812a3338 kd> f05574b0 f05572f0 812a50f8 kd> f05572f0 f05576b0 f05574b0 kd> f05576b0 f05573b0 f05572f0 kd> f05573b0 f0557450 f05576b0 kd> f0557450 f0557650 f05573b0 kd> f0557650 f07fd150 f0557450 kd> f07fd150 f07fd330 f0557650 kd> f07fd330 ef093848 f07fd150 kd> ef093848 ef05d910 f07fd330 kd> ef05d910 810a6b38 ef093848 kd> 810a6b38 810a6b88 ef05d910 kd> 810a6b88 810a6bd8 810a6b38 kd> 810a6bd8 810a6c28 810a6b88 kd> 810a6c28 eeffeb50 810a6bd8 kd> eeffeb50 eeffebf0 810a6c28 kd> eeffebf0 eeffeba0 eeffeb50 kd> eeffeba0 eeffec40 eeffebf0 kd> eeffec40 eeffec90 eeffeba0 kd> eeffec90 80473378 eeffec40 kd> 80473378 8047f8d0 eeffec90 // 我们又看到了 80473378 ,表示链已经循环了 LookasideList 的项 LookasideList 的项通过 +00 struct _SINGLE_LIST_ENTRY *Next 的链,链在一起。为空表示链结束。 下面使用 kd 举一个例子。 kd> !lookaside 810eae68 !lookaside 810eae68 Lookaside \"\" @ 810eae68 \"Usqm\" Type = 0021 PagedPool Current Depth = 4 Max Depth = 4 Size = 48 Max Alloc = 192 AllocateMisses = 922 FreeMisses = 918 TotalAllocates = 56869 TotalFrees = 56869 Hit Rate = 98% Hit Rate = 98% // 810eae68 处是 PAGED_LOOKASIDE_LIST +0 处的4个字节就是链的开始 kd> dd 810eae68+0 l 1 dd 810eae68+0 l 1 810eae68 e2f44428 // e2f44428 是指向Buf的指针,之前的4个字节是维护该Buf结构中的Tag // Buf的首地址开始的4个字节用来形成链 kd> db e2f44428-4 l 4 ; dd e2f44428 l 1 db e2f44428-4 l 4 ; dd e2f44428 l 1 e2f44424 55 73 71 6d Usqm e2f44428 e2fdc2a8 kd> db e2fdc2a8-4 l 4 ; dd e2fdc2a8 l 1 db e2fdc2a8-4 l 4 ; dd e2fdc2a8 l 1 e2fdc2a4 55 73 71 6d Usqm e2fdc2a8 e13a2c68 kd> db e13a2c68-4 l 4 ; dd e13a2c68 l 1 db e13a2c68-4 l 4 ; dd e13a2c68 l 1 e13a2c64 55 73 71 6d Usqm e13a2c68 e16d4f88 kd> db e16d4f88-4 l 4 ; dd e16d4f88 l 1 db e16d4f88-4 l 4 ; dd e16d4f88 l 1 e16d4f84 55 73 71 6d Usqm e16d4f88 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函数申请一块。不为空就把这一块提交。 欢迎交流,欢迎交朋友, 欢迎访问 http://jiurl.yeah.net http://jiurl.cosoft.org.cn/forum |
|
沙发#
发布于:2003-08-07 11:05
真的不错,我帮你顶 :)
|
|
板凳#
发布于:2003-08-08 19:22
http://jiurl.yeah.net 上有几篇文章还不错 |
|