Windows内存管理(1)

news/2024/7/20 12:37:57 标签: 数据结构与算法, 内存管理, 大数据

1.      分配内核内存

Windows驱动程序使用的内存资源非常珍贵,分配内存时要尽量节约。和应用程序一样,局部变量是存放在栈空间中的。但栈空间不会像应用程序那么大,所以驱动程序不适合递归调用或者局部变量是大型数据结构。如果需要大型数据结构,我们可以在堆中申请。

堆中申请的函数有以下几个:

1PVOID 
        ExAllocatePool(
           IN POOL_TYPE  PoolType,
           IN SIZE_T  NumberOfBytes
           );

         2PVOID 
       ExAllocatePoolWithTag(
        IN POOL_TYPE  PoolType,
        IN SIZE_T  NumberOfBytes,
       IN ULONG  Tag
        );

3 PVOID 
      ExAllocatePoolWithQuota(
       IN POOL_TYPE  PoolType,
      IN SIZE_T  NumberOfBytes
      );

    4PVOID 
      ExAllocatePoolWithQuotaTag(
      IN POOL_TYPE  PoolType,
      IN SIZE_T  NumberOfBytes,
      IN ULONG  Tag
       );

PoolType:是个枚举变量,如果此值为NonPagedPool,则分配非分页内存。如果此值为PagedPool,则分配的内存为分页内存。

NumberOfBytes是分配的内存大小,最好是4的整数倍。

返回值是分配的内存地址,一定是内核模式下的地址。如果返回0,则代表分配失败。

 

将分配的内存进行回收的函数如下:

1VOID 
    ExFreePool(
    IN PVOID  P
    );

2NTKERNELAPI
VOID
  ExFreePoolWithTag(
    IN PVOID  P,
    IN ULONG  Tag 
    ); 

 

 

2. 在驱动中使用链表

在驱动程序开发中,经常要使用链表这种数据结构。DDK为用户提供两种链表的数据结构,简化了对链表的操作。

下面主要讲的是双向链表。

1)链表结构

DDK提供了标准的双向链表。双向链表可以将链表形成一个环。BLINK指针指向前一个元素。FLINK指针指向下一个元素。

Windows<a class=内存管理(1)--分配内核内存 和 使用链表 - Fly - 从C开始" src="http://img396.ph.126.net/yaWd3g4mJENG-yHHHDHdfw==/1084523085267269536.jpg" />
 

DDK提供的双向链表的数据结构如下:

typedef struct _LIST_ENTRY {
  struct _LIST_ENTRY *Flink;
  struct _LIST_ENTRY *Blink;
} LIST_ENTRY, *PLIST_ENTRY;

 

2)链表初始化

每个双向链表都是以一个链表头作为链表的第一个元素。初次使用链表头需要进行初始化。主要是将链表头的FLINKBLINK两个指针指向自己。表示链表头所代表的链是空链。

链表头初始化函数如下:

VOID 
 InitializeListHead(
  IN PLIST_ENTRY  ListHead
  );

Windows<a class=内存管理(1)--分配内核内存 和 使用链表 - Fly - 从C开始" src="http://img153.ph.126.net/ohIBRtOJrGbbUafe_RG80w==/3029796649314941017.png" />
  如何判断链表是否为空,可以判断链表头的 BLINK FLINK 指针是否指向自己。 DDK 为我们提供了一个宏简化了这种检查:

BOOLEAN 
  IsListEmpty(
    IN PLIST_ENTRY  ListHead
    );

 

上面定义的链表头只有前后指针而没有数据元素。因此我们需要自己定义链表中每个元素的数据类型。并将LIST_ENTRY结构作为自定义结构的一个子域。LIST_ENTRY的作用就是将自定义数据结构串成一个链表。

例如:

typedef struct _MYDATASTRUCT{

LIST_ENTRY  ListEntry;

ULONG  x;

ULONG  y;

}MYDATASTRUCT,*PMYDATASTRUCT;

 

3)插入删除链表元素

从链表头部插入:

VOID 
  InsertHeadList(
    IN PLIST_ENTRY  ListHead,
    IN PLIST_ENTRY  Entry
    );

用法如下:

InsertHeadList(&head, &mydata->ListEntry);

其中,headLIST_ENTRY结构的链表头,mydata是自定义的数据结构。

 

从链表尾部插入:

VOID 
  InsertTailList(
    IN PLIST_ENTRY  ListHead,
    IN PLIST_ENTRY  Entry
    );

 

从链表中删除:

PLIST_ENTRY 
  RemoveHeadList(
    IN PLIST_ENTRY  ListHead
    );

 

PLIST_ENTRY 
  RemoveTailList(
    IN PLIST_ENTRY  ListHead
    );

 

这两个函数返回的是从链表删除下来的元素中的LIST_ENTRY子域。当我们想获得用户自定义数据结构的指针时,有两种情况:

(1)   自定义数据结构的第一个字段就是LIST_ENTRY结构,如下:

typedef struct _MYDATASTRUCT{

LIST_ENTRY  ListEntry;

ULONG  x;

ULONG  y;

}MYDATASTRUCT,*PMYDATASTRUCT;

这时,要得到自定义的数据结构可以如下:

PLIST_ENTRY pEntry = RemoveHeadList&head);

PMYDATASTRUCT pMyData = PMYDATASTRUCTpEntry

 

(2)   自定义数据结构的第一个字段就不是LIST_ENTRY结构,如下:

typedef struct _MYDATASTRUCT{

ULONG  x;

ULONG  y;

LIST_ENTRY  ListEntry;

}MYDATASTRUCT,*PMYDATASTRUCT;

此时,前面的方法就是错误的,我们可以使用DDK为我们提供的一个宏

PCHAR 
  CONTAINING_RECORD(
    IN PCHAR  Address,
    IN TYPE  Type,
    IN PCHAR  Field
    );

要得到自定义的数据结构可以如下:

PLIST_ENTRY pEntry = RemoveHeadList&head);

PMYDATASTRUCT pMyData =

CONTAINING_RECORDpEntry MYDATASTRUCT, ListEntry

 

注意DDK建议无论自定义数据结构的第一个字段是否为LIST_ENTRY结构,最好都使用CONTAINING_RECORD宏得到自定义数据结构的指针。

测试代码:

typedef struct _MYDATASTRUCT{

     ULONG number;

     LIST_ENTRY ListEntry;

}MYDATASTRUCT, *PMYDATASTRUCT;

 

#pragma INITCODE

VOID LinkListTest()

{

     KdPrint(("进入双向链表测试函数!\n"));

     LIST_ENTRY ListHead;

     InitializeListHead(&ListHead);

    

     PMYDATASTRUCT pData;

     ULONG i;

     KdPrint(("开始往链表中插入数据!\n"));

     for (i=1; i<=10; i++)

     {

         pData = (PMYDATASTRUCT)ExAllocatePool(PagedPool, sizeof(MYDATASTRUCT));

         pData->number = i;

        

         InsertHeadList(&ListHead, &pData->ListEntry);

     }

     KdPrint(("插入数据完毕!\n"));

     KdPrint(("-----------------------------------------------------------------\n"));

     KdPrint(("开始删除链表中的数据!\n"));

     while(!IsListEmpty(&ListHead))

     {

         PLIST_ENTRY pListEntry = RemoveHeadList(&ListHead);

         pData = CONTAINING_RECORD(pListEntry, MYDATASTRUCT, ListEntry);

         KdPrint(("Remove %d element.\n", pData->number));

         ExFreePool(pData);

     }

     KdPrint(("删除链表中的数据完毕!\n"));

     KdPrint(("-----------------------------------------------------------------\n"));

}

Windows<a class=内存管理(1)--分配内核内存 和 使用链表 - Fly - 从C开始" src="http://img.ph.126.net/qpKyVUerlSVAb52DNAQDkg==/2306687434144405948.png" />

http://www.niftyadmin.cn/n/1183296.html

相关文章

Ubuntu 10.10 Netbook 安装图解

友情提示&#xff1a;安装前请先完整的看一遍&#xff0c;以免发生问题&#xff0c;因为时间有限&#xff0c;只是简单的把过程记录下来&#xff0c;另外&#xff0c;由于截图的需要&#xff0c;本次安装是在VirtualBox虚拟机中进行的&#xff0c;对虚拟机或安装过程中有什么问…

最常用的编写Linux脚本命令和语法

接受用户的参数 [rootlinuxprobe ~]# vim example.sh #!/bin/bash echo "当前脚本名称为 $0" echo "总共有 $# 个参数&#xff0c;分别是 $*。" echo "第1个参数为 $1&#xff0c;第5个为 $5。" [rootlinuxprobe ~]# sh example.sh one two thr…

04SpringMVC--JSON使用

目录 JSON的要求和语法格式&#xff1a; JSON字符串转化为JS对象&#xff0c;使用JSON.parse()方法 JS字符串转化为JSON对象&#xff0c;使用JSON.stringify()方法 JSON 返回字符串 JSON处理时间Date 封装成工具类 JSON的要求和语法格式&#xff1a; 对象表示为键值对数据…

WordPress博客中添加博客描述(description)和关键字(keywords)

开博有几个月了&#xff0c;博客描述(description)和博客关键字(keywords)一直没有添加&#xff0c;今天&#xff0c;抽出点时间&#xff0c;终于添加上了&#xff0c;效果可以通过(右键->查看源代码)查看。 在header.php(一般是该文件)的<title></title>标签对…

算法导论-15.5-4

Exercises 15.5-4 Knuth has shown that there are always roots of optimal subtrees such that root[i,j-1]<root[i,j]<root[i1,j] for all 1<i<n. Use this fact to modify the OPTIMAL-BST procedure to run in Θ(n^2) time. ————————————————…

个人常用的高效工具

火萤酱 官网主页 http://www.huoying666.com/ 该工具可以快速的搜索电脑内的所有内容&#xff0c;很快速。 基于 EveryThing 软件改造&#xff0c;但是比 EveryThing 颜值更高&#xff08;这一点就够了&#xff09;&#xff0c;并且能够改变平时的搜索习惯。 完美解码 官网…

[转]synchronized用法简介

from&#xff1a;http://www.niwota.com/submsg/2582768/ synchronized关键字的作用域有二种&#xff1a; 1&#xff09;是某个对象实例内&#xff0c;synchronized aMethod(){}可以防止多个线程同时访问这个对象实例的synchronized方法&#xff08;如果一个对象实例有多个sync…

05SpringMVC---Ajax的使用

目录 ajax 是一种浏览器通过 js 异步发起请求&#xff0c;局部更新页面的技术。 使用Ajax需要导入jQuery 特别注意&#xff1a; jQuery 中的 AJAX 请求格式 常用案例&#xff1a;表单回显数据 常用案例&#xff1a;用户账号密码的验证 ajax 是一种浏览器通过 js 异步发起…