📄 jiurl玩玩win2k内存篇 lookasidelist.htm
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0076)http://jiurl.cosoft.org.cn/jiurl/document/JiurlPlayWin2k/MmLookasideList.htm -->
<HTML><HEAD><TITLE>JIURL玩玩Win2k内存篇 LookasideList</TITLE>
<META content="text/html; charset=gb2312" http-equiv=Content-Type>
<STYLE type=text/css>.title {
FONT-FAMILY: "黑体", Arial, sans-serif; FONT-SIZE: 21px; FONT-WEIGHT: bold; LINE-HEIGHT: 48px; TEXT-DECORATION: none
}
.author {
FONT-FAMILY: "宋体"; FONT-SIZE: 12px; LINE-HEIGHT: 16px
}
.content {
FONT-SIZE: 14px; LINE-HEIGHT: 20px
}
</STYLE>
<META content="MSHTML 5.00.2614.3500" name=GENERATOR></HEAD>
<BODY bgColor=#f7f7f7 topMargin=5>
<DIV align=center>
<CENTER>
<TABLE border=0 cellPadding=0 cellSpacing=0 height=29 width="96%">
<TBODY>
<TR>
<TD class=title height=41 width="100%">
<P align=center><FONT face=宋体>JIURL玩玩Win2k内存篇
LookasideList</FONT></P></TD></TR></CENTER>
<TR>
<TD class=author height=9 width="100%">
<P align=center><FONT face=宋体>作者: <A
href="mailto:jiurl@mail.china.com">JIURL</A> </FONT></P></TD></TR>
<TR>
<TD class=author height=6 width="100%">
<P align=center><FONT
face=宋体>
主页: <A href="http://jiurl.yeah.net/">http://jiurl.yeah.net/</A>
</FONT></P></TD></TR>
<TR>
<TD class=author height=2 width="100%">
<P align=center><FONT face=宋体> 日期: 2003-7-30</FONT>
</P></TD></TR></TBODY></TABLE></DIV>
<DIV align=center>
<CENTER>
<TABLE border=0 cellPadding=0 cellSpacing=0 height=1 width="96%">
<TBODY>
<TR>
<TD height=1 width="100%">
<HR color=#396da5 SIZE=3>
</TD></TR></TBODY></TABLE></CENTER></DIV>
<DIV align=center>
<TABLE border=0 cellPadding=0 cellSpacing=0 class=content height=12000
width="96%">
<TBODY>
<TR>
<TD height=1066 vAlign=top width="131%"><B>系统的堆的简介</B>
<P> 系统的堆是系统的数据动态申请和释放的地方。Win2k 把系统堆叫做
pool。根据是否可以被换出物理内存,分为 PagedPool 和 NonPagedPool。</P>
<P><B>LookasideList</B></P>
<P><B> </B>Windows 2000 中有很多种结构,这些结构需要动态申请。也就是在系统的 pool
中申请。在 pool 中申请和释放内存都是比较慢的,因为申请的时候需要在 pool
中寻找合适大小的空闲块,释放的时候还要考虑合并空闲块,等等繁琐的操作。系统中有很多很多的固定大小的结构需要动态分配,为了提高效率,系统使用了
LookasideList 。</P>
<P> Windows 2000 中有很多的 LookasideList 。某种 LookasideList
申请固定大小的存。LookasideList 从 Paged pool 或者 Nonpaged pool 中申请内存。对于
LookasideList 上的块释放的时候,它并不是被直接释放到 pool 中,而有可能放在 LookasideList
上,这样如果再有申请的话,就不用再去 pool 中查找合适大小的空闲块,而可以直接取走使用了。也就是申请的时候,仍然是去 pool
中申请一块一定大小的内存。但是释放的时候,很有可能并不释放回堆里去,而是被 LookasideList
保留下来,供再申请的时候使用。后面我们将会发现系统中 LookasideList
的数量很多,如果申请过的块都不被释放的话,那不是要白白占用很多内存,有可能导致别人的新的申请申请不到内存?不必担心,每个 LookasideList
最多只保留很少的几块,如果超过,就会释放回 pool 里去。系统也会定时检查。</P>
<P> Windows 2000 把很多 LookasideList 链在两个链上。根据该
LookasideList 是从 Paged pool 还是从 Nonpaged pool 中申请内存。从 Paged pool 中申请内存的
LookasideList 链在 PagedLookasideList 上。<BR>从 Nonpaged pool 中申请内存的
LookasideList 链在 NPagedLookasideList 上。</P>
<P>在 ntddk.h 中有两种 LookasideList (NPAGED_LOOKASIDE_LIST 和
PAGED_LOOKASIDE_LIST) 及其相关结构的定义。通过 kd 也可以得到他们的结构定义。</P>
<P>typedef struct _NPAGED_LOOKASIDE_LIST {<BR>GENERAL_LOOKASIDE
L;<BR>KSPIN_LOCK Lock;<BR>} NPAGED_LOOKASIDE_LIST,
*PNPAGED_LOOKASIDE_LIST;<BR><BR><BR>typedef struct _PAGED_LOOKASIDE_LIST
{<BR>GENERAL_LOOKASIDE L;<BR>FAST_MUTEX Lock;<BR>} PAGED_LOOKASIDE_LIST,
*PPAGED_LOOKASIDE_LIST;</P>
<P>kd> !strct GENERAL_LOOKASIDE<BR>!strct GENERAL_LOOKASIDE<BR>struct
_GENERAL_LOOKASIDE (sizeof=72)<BR>+00 union _SLIST_HEADER ListHead<BR>+00
uint64 Alignment<BR>+00 struct _SINGLE_LIST_ENTRY Next<BR>+00 struct
_SINGLE_LIST_ENTRY *Next<BR>+04 uint16 Depth<BR>+06 uint16 Sequence<BR>+08
uint16 Depth<BR>+0a uint16 MaximumDepth<BR>+0c uint32
TotalAllocates<BR>+10 uint32 AllocateMisses<BR>+10 uint32
AllocateHits<BR>+14 uint32 TotalFrees<BR>+18 uint32 FreeMisses<BR>+18
uint32 FreeHits<BR>+1c int32 Type<BR>// 表明是 NPAGED 还是 PAGED。 为0表示NPAGED
。为1表示PAGED。<BR>+20 uint32 Tag<BR>// 4个字节,通常放入4个字母来作为标记。比如
ObpCreateInfoLookasideList 使用 "ObCi"。<BR>+24 uint32 Size<BR>// 这个
LookasideList 上每项的大小。<BR>+28 function *Allocate<BR>// 申请函数,通常放
ExAllocatePoolWithTag<BR>+2c function *Free<BR>// 释放函数,通常放
ExFreePool<BR>+30 struct _LIST_ENTRY ListEntry<BR>+30 struct _LIST_ENTRY
*Flink<BR>+34 struct _LIST_ENTRY *Blink<BR>// 这里把同一种类型(NPAGED 或者 PAGED)的
LookasideList 链在一起。<BR>+38 uint32 LastTotalAllocates<BR>+3c uint32
LastAllocateMisses<BR>+3c uint32 LastAllocateHits<BR>+40 uint32
Future[2]</P>
<P>typedef struct _SINGLE_LIST_ENTRY {<BR>struct _SINGLE_LIST_ENTRY
*Next;<BR>} SINGLE_LIST_ENTRY, *PSINGLE_LIST_ENTRY;</P>
<P>下面我们使用 kd 分别遍历这两个链表</P>
<P><B>遍历 PagedLookasideList</B><BR><BR>kd> ?
ExPagedLookasideListHead<BR>? ExPagedLookasideListHead<BR>Evaluate
expression: -2142817432 = 80473368<BR>// 全局变量
ExPagedLookasideListHead <BR><BR>kd> !strct LIST_ENTRY
ExPagedLookasideListHead<BR>!strct LIST_ENTRY
ExPagedLookasideListHead<BR>struct _LIST_ENTRY (sizeof=8)<BR>+0 struct
_LIST_ENTRY *Flink = 8046A9D0<BR>+4 struct _LIST_ENTRY *Blink =
810EAF38<BR>// PagedLookasideList 链上的 PAGED_LOOKASIDE_LIST 结构中的 LIST_ENTRY
ListEntry<BR><BR>!strct PAGED_LOOKASIDE_LIST<BR>struct
_PAGED_LOOKASIDE_LIST (sizeof=104)<BR>...<BR>+30 struct _LIST_ENTRY
ListEntry<BR>...<BR><BR>kd> ? 8046A9D0-30<BR>? 8046A9D0-30<BR>Evaluate
expression: -2142852704 = 8046a9a0<BR><BR>// 验证一下<BR>kd> !lookaside
8046a9a0<BR>!lookaside 8046a9a0<BR><BR>Lookaside "" @ 8046a9a0
"TunL"<BR>Type = 0001 PagedPool<BR>Current Depth = 1 Max Depth = 4<BR>Size
= 136 Max Alloc = 544<BR>AllocateMisses = 293 FreeMisses =
283<BR>TotalAllocates = 478 TotalFrees = 469<BR>Hit Rate = 38% Hit Rate =
39%</P>
<P>kd> !strct PAGED_LOOKASIDE_LIST 8046a9a0<BR>!strct
PAGED_LOOKASIDE_LIST 8046a9a0<BR>struct _PAGED_LOOKASIDE_LIST
(sizeof=104)<BR>+00 struct _GENERAL_LOOKASIDE L<BR>+00 union _SLIST_HEADER
ListHead<BR>+00 uint64 Alignment = 01730001e35116c8<BR>+00 struct
_SINGLE_LIST_ENTRY Next<BR>+00 struct _SINGLE_LIST_ENTRY *Next =
E35116C8<BR>+04 uint16 Depth = 0001<BR>+06 uint16 Sequence = 0173<BR>+08
uint16 Depth = 0004<BR>+0a uint16 MaximumDepth = 0100<BR>+0c uint32
TotalAllocates = 000001de<BR>+10 uint32 AllocateMisses = 00000125<BR>+10
uint32 AllocateHits = 00000125<BR>+14 uint32 TotalFrees = 000001d5<BR>+18
uint32 FreeMisses = 0000011b<BR>+18 uint32 FreeHits = 0000011b<BR>+1c
int32 Type = 00000001 // 1=PagedPool<BR>+20 uint32 Tag = 4c6e7554<BR>+24
uint32 Size = 00000088 // 0x88=136<BR>+28 function *Allocate =
80466C80<BR>+2c function *Free = 80467297<BR>+30 struct _LIST_ENTRY
ListEntry<BR>+30 struct _LIST_ENTRY *Flink = 804734B0<BR>+34 struct
_LIST_ENTRY *Blink = 80473368<BR>+38 uint32 LastTotalAllocates =
000001dd<BR>+3c uint32 LastAllocateMisses = 00000125<BR>+3c uint32
LastAllocateHits = 00000125<BR>+40 uint32 Future[2] = 00000000 00000000
.... ....<BR>+48 struct _FAST_MUTEX Lock<BR>+48 int32 Count =
00000001<BR>+4c struct _KTHREAD *Owner = 00000000<BR>+50 uint32 Contention
= 00000000<BR>+54 struct _KEVENT Event<BR>+54 struct _DISPATCHER_HEADER
Header<BR>+54 byte Type = 01 .<BR>+55 byte Absolute = 00 .<BR>+56 byte
Size = 04 .<BR>+57 byte Inserted = 00 .<BR>+58 int32 SignalState =
00000000<BR>+5c struct _LIST_ENTRY WaitListHead<BR>+5c struct _LIST_ENTRY
*Flink = 8046A9FC //<BR>+60 struct _LIST_ENTRY *Blink = 8046A9FC<BR>+64
uint32 OldIrql = 00000000</P>
<P>kd> dd ExPagedLookasideListHead l 2<BR>dd ExPagedLookasideListHead l
2<BR>80473368 8046a9d0 810eaf38<BR>// 记住我们是从 ExPagedLookasideListHead
80473368 开始的,当我们再看到 80473368<BR>// 就表示链已经循环了。<BR><BR>kd> dd $p l
2<BR>dd $p l 2<BR>8046a9d0 804734b0 80473368<BR><BR>kd><BR>804734b0
80473730 8046a9d0<BR><BR>kd><BR>80473730 804802f0
804734b0<BR><BR>kd><BR>804802f0 80480a90
80473730<BR><BR>kd><BR>80480a90 fcccd4b0
804802f0<BR><BR>kd><BR>fcccd4b0 fcccd590
80480a90<BR><BR>kd><BR>fcccd590 810eba38
fcccd4b0<BR><BR>kd><BR>810eba38 810eb918
fcccd590<BR><BR>kd><BR>810eb918 810eb898
810eba38<BR><BR>kd><BR>810eb898 810eb818
810eb918<BR><BR>kd><BR>810eb818 810eb798
810eb898<BR><BR>kd><BR>810eb798 810eb718
810eb818<BR><BR>kd><BR>810eb718 810eb698
810eb798<BR><BR>kd><BR>810eb698 810ea038
810eb718<BR><BR>kd><BR>810ea038 810eafb8
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -