Windows内存管理 - Lookaside结构

文章讲述了频繁申请和回收内存可能导致内存空洞,影响内存利用率。DDK提供的Lookaside结构通过预先分配和智能回收内存,有效解决了这个问题。介绍了Lookaside对象的初始化、内存申请、回收和删除方法,以及一个使用示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        频繁申请和回收内存,会导致在内存上产生大量的内存“空洞”,从而导致最终无法申请内存。DDK为程序员提供了Lookaside结构来解决这个问题。

1. 频繁申请内存的弊端

        频繁地申请内存,会导致一个问题,就是在内存中产生“空洞”。如图1显示了这种情况,在内存中先后申请三块内存。最开始可用的内存是连续的。当某个时刻内存块2被回收以后,如果系统想分配一块略微大于原先内存块2的内存,这时候原先的内存2就不能被申请成功。因此,频繁地申请、回收内存会导致在内存上产生大量的内存“空洞”。

        如果系统中存在大量的内存“空洞”,即使内存中有大量的可用内存,也会导致申请内存失败。在操作系统空闲的时候,系统会整理内存中的“空洞”,将内存中的“空洞”进行合并。

2. 使用Lookaside

        如果驱动程序需要频繁地从内存中申请、回收固定大小的内存,DDK提供了一种机制来解决这个问题,这就是使用Lookaside对象。

        可以将Lookaside对象想象成一个内存容器。在初始的时候,它先向Windows申请了一块比较大的内存。以后程序员每次申请内存的时候,不是直接向Windows申请内存,而是向Lookaside对象申请内存。Lookaside对象会智能地避免产生内存“空洞”。如果Lookaside对象内部的内存不够用时,它会向操作系统申请更多的内存。当Lookaside对象内部有大量的未使用的内存时,它会自动
让Windows回收一部分内存。总之,Lookaside是一个自动的内存分配容器。通过对Lookaside对象申请内存,效率要高于直接向Windows申请内存。Lookaside一般会在以下情况使用:

    (1). 程序员每次申请固定大小的内存。
    (2). 申请和回收的操作十分频繁。
    
        如果程序员遇到上述两种情况,可以考虑使用Lookaside对象。驱动程序中的运行效率是程序员必须考虑的问题。如果驱动程序的运行效率低,会严重影响到操作系统的性能。使用Lookaside
对象,首先要初始化Lookaside对象,有以下两个函数可以使用:

    VOID ExInitializeNPagedLookasideList (
            __out PNPAGED_LOOKASIDE_LIST Lookaside,
            __in_opt PALLOCATE_FUNCTION Allocate,
            __in_opt PFREE_FUNCTION Free,
            __in ULONG Flags,
            __in SIZE_T Size,
            __in ULONG Tag,
            __in USHORT Depth
            );

    VOID ExInitializePagedLookasideList (
            __out PPAGED_LOOKASIDE_LIST Lookaside,
            __in_opt PALLOCATE_FUNCTION Allocate,
            __in_opt PFREE_FUNCTION Free,
            __in ULONG Flags,
            __in SIZE_T Size,
            __in ULONG Tag,
            __in USHORT Depth
            );   

 
这两个函数分别是对非分页和分页Lookaside对象进行初始化。


在初始化完Lookaside对象后,可以进行申请内存的操作了,有以下两个函数。

    PVOID ExAllocateFromNPagedLookasideList (
            __inout PNPAGED_LOOKASIDE_LIST Lookaside
            )            

    PVOID ExAllocateFromPagedLookasideList (
            __inout PPAGED_LOOKASIDE_LIST Lookaside
            );  

         
这两个函数分别是对非分页内存和分页内存的申请。


对Lookaside对象回收内存的操作,有以下两个函数:

    VOID ExFreeToNPagedLookasideList (
        __inout PNPAGED_LOOKASIDE_LIST Lookaside,
        __in PVOID Entry
        );

    VOID ExFreeToPagedLookasideList (
        __inout PPAGED_LOOKASIDE_LIST Lookaside,
        __in PVOID Entry
        );


这两个函数分别是对非分页内存和分页内存的回收。


在使用完Lookaside对象后,需要删除Lookaside对象,有以下两个函数:

    VOID ExDeleteNPagedLookasideList (
        __inout PNPAGED_LOOKASIDE_LIST Lookaside
        );    

    VOID ExDeletePagedLookasideList (
        __inout PPAGED_LOOKASIDE_LIST Lookaside
        );


这两个函数分别是对非分页和分页Lookaside对象删除。    

使用示例:

#define ARRAY_NUMBER 50

#pragram INITCODE
VOID LookasideTest()
{
    // 初始化Lookaside对象
    PAGED_LOOKASIDE_LIST pageList;
    ExInitializePagedLookasideList(&pageList, NULL, NULL, 0, sizeof(MYDATASTRUCT), '1234', 0);


    PMYDATASTRUCT MyObjectArray(ARRAY_NUMBER);

    // 模拟频繁申请内存
    for (int i = 0; i < ARRAY_NUMBER; i++)
    {
        MyObjectArray[i] = (PMYDATASTRUCT)ExAllocateFromPagedLookasideList(&pageList);
    }

    // 模拟频繁回收内存
    for (int i = 0; i < ARRAY_NUMBER; i++)
    {
        ExFreeToPagedLookasideList(&pageList, MyObjectArray[i]);
        MyObjectArray[i] = NULL;
    }

    // 删除Lookaside对象
    ExDeletePagedLookasideList(&pageList);
}


    

    
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WendyWJGu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值