章五.Windows内存管理(下)

以下内容全部来自《Windows驱动开发技术详解》,作者张帆、史彩成等,属摘抄型笔记。

///

1.频繁的申请、回收内存会导致在内存上产生大量的内存“空洞”,以致于其他申请内存失败。


2.Lookaside对象作为内存池,先向Windows申请一块较大的内存,之后程序每次申请内存的时候,不直接向Windows申请内存,而是向Lookaside对象申请内存。


3.Lookaside对象内部的内存不够用时,会向操作系统申请更多内存,当Lookaside对象内部有大量的未使用的内存时,它会自动让Windows回收一部分内存。


4.Lookaside适用于以下情况:程序员每次申请固定大小的内存,申请和回收的操作十分频繁。


5.首先需要初始化Lookaside对象,以下函数分别对非分页和分页Lookaside对象进行初始化。

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

NTKERNELAPI VOID ExInitializeNPagedLookasideList(IN PNPAGED_LOOKASIDE_LIST Lookaside,
												  IN PALLOCATE_FUNCTION Allocate,
												  IN PFREE_FUNCTION Free,
												  IN ULONG Flags,
												  IN SIZE_T Size,
												  IN ULONG Tag,
												  IN USHORT Depth);

NTKERNELAPI VOID ExInitializePagedLookasideList(IN PPAGED_LOOKASIDE_LIST Lookaside,
												IN PALLOCATE_FUNCTION Allocate,
												IN PFREE_FUNCTION Free,
												IN ULONG Flags,
												IN SIZE_T Size,
												IN ULONG Tag,
												IN USHORT Depth);
初始化完Lookaside对象后,可以进行申请内存的操作,下面两个函数分别对非分页内存和分页内存申请。

__inline PVOID ExAllocateFromNPagedLookasideList(IN PNPAGED_LOOKASIDE_LIST Lookaside);
NTKERNELAPI PVOID ExAllocateFromPagedLookasideList(IN PPAGED_LOOKASIDE_LIST Lookaside);

使用如下函数进行内存回收。

NTKERNELAPI VOID ExFreeToPagedLookasideList(IN PPAGED_LOOKASIDE_LIST Lookaside,
											IN PVOID Entry);

__inline VOID ExFreeToPagedLookasideList(IN PPAGED_LOOKASIDE_LIST Lookaside,
										 IN PVOID Entry);
最后不使用该对象后,要进行内存释放,分别使用如下函数。

NTKERNELAPI VOID ExDeleteNPagedLookasideList(IN PNPAGED_LOOKASIDE_LIST Lookaside);
NTKERNELAPI VOID ExDeletePagedLookasideList(IN PPAGED_LOOKASIDE_LIST Lookaside);

PS:如果后续频繁使用Lookaside对象,会对inline的内容再次进行学习的,现在就定性的了解下,有需要再说了。


6.运行时函数,这个地方还是对比应用程序的运行时函数,在需要的时候Google吧,原理性的东西不多就不一一列举了。


7.返回值

NTSTATUS 是一个32位整数,每位有不同的含义,具体参考NTDDK说明。




8.内存可用性

在驱动程序中,如果某段内存是只读的,而驱动程序试图去进行写操作,会导致系统的崩溃。DDK提供函数,检测内段可读写特性。

NTKERNELAPI VOID NTAPI ProbeForRead(IN CONST VOID *Address,
									IN SIZE_T Length,
									IN ULONG Alignment);

NTKERNELAPI VOID NTAPI ProbeForWrite(IN PVOID Address,
									 IN SIZE_T Length,
									 IN ULONG Alignment);
三个参数分别为:内存地址,被检测内存的长度,该段内存的对齐方式。

但是该函数没有返回值,对于这个函数的使用,还需要参考机构化异常处理。


9.结构化异常处理(try-except块)

机构化异常处理(Structured Exception Handling,SEH)是微软编译器提供的独特处理机制,这种处理方式能在一定程度上在出现错误的情况下,避免程序崩溃。

a.异常:有点类似中断的概念,当程序中某种错误触发一个异常,操作系统会寻找处理这个异常的处理函数,如果程序提供错误处理函数,则进入错误处理函数;如果没有提供处理函数,则由操作系统的默认错误处理函数处理。而在内核中,错误处理往往很简单,直接BSOD。

b.回卷:程序执行到摸个地方出现异常错误时,系统会寻找出错点是否处于一个try()块中,并进入try块提供的异常处理代码,如果当前try块没有提供异常处理,则会像更外一层的try块,寻找异常处理函数。直到最外层try()块也没有提供异常处理代码,则交由操作系统处理。(这种向外层寻找异常处理的机制,被称为回卷)

__try
{

}
__except(filter_value)
{

}
在try块包围的代码块中如果出现异常,会根据filter_value的数值,判断是否需要在__except中处理。

有如下三种可能:

#define EXCEPTION_EXECUTE_HANDLER       1
#define EXCEPTION_CONTINUE_SEARCH       0
#define EXCEPTION_CONTINUE_EXECUTION    -1
1).EXCEPTION_EXECUTE_HANDLER,进入到__except块中处理,处理完成后不再转入try中,继续向下执行。

2).EXCEPTION_CONTINUE_SEARCH,不使用__except块中处理,直接向外层回卷,如果在最外层,直接交由操作系统进行处理。

3).EXCEPTION_CONTINUE_EXECUTION,此在驱动中很少见,重复先前错误的指令。

#include <ntddk.h>

VOID ProbeTest()
{
	PVOID badPointer = NULL;
	KdPrint(("Enter ProbeTest\n"));
	__try
	{
		KdPrint(("Enter __try block\n"));

		//判断空指针是否可读,触发异常
		ProbeForWrite(badPointer, 0x100, 4);

		//由于触发异常,后续代码无法被执行
		KdPrint(("Leave __try block\n"));
	}
	__except(EXCEPTION_EXECUTE_HANDLER)
	{
		KdPrint(("CASE:EXCEPTION_EXECUTE_HANDLER\n"));
	}
}

VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{

	KdPrint(("DriverUnload"));
}


NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath)
{
	KdPrint(("DriverEntey\n"));
	pDriverObject->DriverUnload = DriverUnload;
	ProbeTest();
	return STATUS_SUCCESS;
}

除了读写内存外,还可以主动出发异常,例如ExRaiseStatus函数,可以指定状态码触发异常。


10.结构化异常处理(try-finally块)

结构化异常处理还有另外一种使用方法,使用try-finally块,强迫函数在退出前执行一段代码。

NTSTATUS TryFinallyTest()
{
	NTSTATUS ns = STATUS_SUCCESS;
	__try
	{
		return STATUS_SUCCESS;
	}
	__finally
	{
		KdPrint(("Enter Finally block\n"));
	}
}
对于finally块,触发异常或者退出时都会执行,较适合用做资源回收。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值