何谓可分页和非分页内存

何谓可分页和非分页内存

1)默认情况下,内核加载器会加载所有的代码部分和全局数据到非分页内存中。而且,加载器是一次加载整个驱动的可执行文件,包括相关的DLL。加载后,内核加载器关闭驱动程序文件,甚至你可以删除当前正在执行的驱动文件。

但是,你可以告诉加载器你希望驱动的哪部分是可分页,所谓可分页,就是可能会被换页出内存(Page out)。可以使用下面的指令来实现:

#define ALLOC_PRAGMA

#pragma alloc_text(PAGE, function_name1)

#pragma alloc_text(PAGE, function_name2)

#endif

由function_namex 指定的函数代码将被放置于可分页内存中。

使数据段可分页,使用下面的编译指令:

#ifdef ALLOC_PRAGMA

#pragma data_seg(PAGE)

// define your pageeble data section module here.

#pragma data_seg()

要注意,绝不能让可能在高的IRQL级别被调用的例程被换出页面。

可以调用MmLockPageableCodeSection 和 MmLockPageableCodeSectionByHandle来锁定被标志为可分页的代码段。

可以调用MmLockPageableDataSection 和 MmLockPageableDataSectionByHandle 来锁定被标志为可分页的数据段

可以调用MmUnlockPageableImageSection 来解除被上面列出的函数锁定的代码或数据段。

可以调用MmPageEntireDriver使整个驱动程序可分页,覆盖使用编译指令修饰的段的页面属性。

可以调用MmResetDriverPaging 把页面属性重设回最初描述的属性。

最后,把那些驱动初始化后不再需要的代码自动丢弃可以使用这些编译指令:

#ifdef ALLOC_PRAGMA

#pragma alloc_text(INIT, DriverEntry)

#pragma alloc_text(INIT, function_name) // function called by driverEntry

#endif

#define PAGEDCODE code_seg("PAGE")

#define LOCKEDCODE code_seg()

#define INITCODE code_seg("INIT")

#define PAGEDDATA data_seg("PAGE")

#define LOCKEDDATA data_seg()

#define INITDATA data_seg("INIT")

2)驱动程序在执行时可能需要动态分配内存空间,这时你要决定需要的是可分页还是不可分页的内存。如果你的驱动在运行中访问内存的时候能够经受页错误,那么尽量使用可分页内存。

注意:大多数低层磁盘和网络驱动通常不能使用可分页内存,因为他们的代码常常在较高的IRQL等级执行而不允许页错误。但是,文件系统(通常比磁盘驱动占用更大,更多资源)有时候可从可分页池中分配一些内存。

非分页内存在整个系统中是一个有限的资源,其数量依赖于系统使用的类型,和系统可用的物理内存。NT提供下面的例程给内核驱动来分配内存:

ExAllocatePool

ExAllocatePoolWithQuota

ExAllocatePoolWithTag

ExAllocatePoolWithQuotaTag

调用这些函数来请求内存时,必须要指定请求的内存的类型:

NonPagedPool    请求分配一个不可分页的内存

PagedPool         请求分配一个可分页的内存

如果你在分配的内存里有任何同步结构的话,决不要分配分页内存。

3)当你的应用访问内存时候可以处理页错误的时候,应该指定这个类型。

NonPagedPoolMustSucceed

在其它方都失败时,而你又必须立即得到内存的时候可以使用这个标志类型。注意这种类型的内存是极度缺乏的资源,可能不足16K。注意,只有在其它途径都失败的时候才使用,如果分配失败,将会导致系统的bugcheck,错误代码MUST_SUCCEED_POOL_EMPTY。

NonPagedPoolCacheAligned

这个标志分配使用数据缓存线的尺寸来在CPU特定的边界对齐的非分页内存。注意这个操作默认是在Intel平台上的 NonPagedPool 分配类型。

PagedPoolCacheAligned

这个标志分配使用数据缓存线的尺寸来在CPU特定的边界对齐的分页内存。

NonPagedPoolCacheAlignedMustSucceed

参考NonPagedPoolMustSucceed 和NonPagedPoolCacheAligned

内存池分配器初始化了一些列表,每个列表包含一种固定大小的块。当你使用上面的函数请求内存时,例程试图分配一个和你请求数量相近的或更大一点的固定大小的块。但是,如果你要求的数量超过一页时,或者超过列表中最大块的大小时,又或者在预先分配的列表中没有可用的块的时候,VMM就会从任何适当类型的系统可用的内存中分配你请求的数量内存给你。

当预先分配的列表空了的时候,VMM会分配至少一页的内存,切分,然后把剩下的数据放进适当的块列表中。但是,当你请求的非分页内存的数量超过PAGE_SIZE时候,内存池分配例程不会切分未使用的部分,这会浪费宝贵的非分页内存。

也可以使用 MmAllocateNonCachedMemory 或 MmAllocateContiguousMemory来分配非分页或物理连续内存。它们通常不使用在文件系统或者过滤驱动中,而是用于执行池例程或者其它结构。

内核驱动如果重复的分配和释放小块的内存(小于一个PAGE_SIZE), 可能导致系统的可用物理内存碎片化。这会给系统带来各种问题,包括降低系统的性能等。有一个方法可以避免系统碎片化,就是预先分配一块合理大小的内存,然后自已管理,在这个预先分配的块中分配和释放小块的内存,但这种方法有可能会浪费核心内存。

4)用池来管理内存

上面提到用预先分配一块合理大小的内存来自已管理,可以避免系统内存碎片。我们可以用池来管理这块预先分配的内存。必须再次强调,预先分配的内存大小必须足够准确,太大会浪费宝贵的资源。

调用 ExAllocatePool 来分配池使用的内存,你要选择从分页或者非分页的池中分配,注意你的内存片基址必须在8字节的边界对齐。

还要分配和初始化一个自旋锁或者使用其它的同步机制来保护对内存块列表的修改。注意不要在比 DISPATCH_LEVEL 更高的 IRQL 等级使用池操作例程,因为在更高的 IRQL等级不能使用同步结构。

然后定义一个ZONE_HEADER结构的全局变量,用来作为这个池的控制结构,并调用ExInitializeZone来初始化池头部。然后,就可以通过调用ExAllocateFromZone和ExInterlockedAllocateFromZone 来分配自已管理的内存块。这两个函数的差别在于后者使用了自旋锁用于操作同步。调用ExFreeToZone 和ExInterlockedFreeToZone来释放分配的内存。

虽然池帮助减少系统内存的碎片,但池还是有一些不足:

1、 驱动程序必须预先为池分配内存,这些内存可能会闲置很久造成内存浪费

2、 你对需要的内存的数量必须相当的精确,在很多时候这个很难做到。

3、 当内存需求增大时,可以扩大池的尺寸,但是却不能减小池的尺寸,直到重启系统5)lookaside lists

lookaside lists 是NT4.0里新的特性,它突破了池的限制。

当你调用 ExInitializeNPagedLookasideList 和ExInitializePagedlookasideList初始化 lookaside lists 时不用预先分配内存,相反,只有当你有真正需要内存的时候才分配。

在初始化时,你必须指定列表的深度,表示尺寸的最大值。相关的函数有ExAllocateFromN-

PagedLookasideList 和ExAllocateFromPagedLookasideList。我们用一个 NPAGED_LOOKASIDE_LIST或 PAGED_LOOKASIDE_LIST结构变量来保存lookaside lists的状态,注意这结构一定要从非分页内存中分配。

转自:

http://blog.csdn.net/lbird/archive/2007/02/12/1508603.aspx

时间: 2024-10-09 21:18:32

何谓可分页和非分页内存的相关文章

分页内存与非分页内存

Windows规定有些虚拟内存可以交换到文件中,这类内存被称为分页内存 有些虚拟内存 永远不会交换到文件中,这些内存叫非分页内存 #define PAGEDCODE  code_seg(“PAGE”);//分页内存 #define LOCKEDCODE  code_seg();//非分页的 #define INITCODE  code_seg(“INIT”); #define PAGEDDATA  data_seg(“PAGE”); #define LOCKEDDATA  data_seg();

Windows内核编程之:分页内存与非分页内存 #define PAGEDCODE code_seg("PAGE") (转)

原文链接:http://blog.chinaunix.net/uid-24504987-id-161192.html Windows规定有些虚拟内存可以交换到文件中,这类内存被称为分页内存 有些虚拟内存永远不会交换到文件中,这些内存叫非分页内存 #define PAGEDCODE  code_seg(“PAGE”);//分页内存 #define LOCKEDCODE  code_seg();//非分页的 #define INITCODE  code_seg(“INIT”); #define PA

[转帖]Linux分页机制之分页机制的演变--Linux内存管理(七)

Linux分页机制之分页机制的演变--Linux内存管理(七) 2016年09月01日 20:01:31 JeanCheng 阅读数:4543 https://blog.csdn.net/gatieme/article/details/52402967 ~ 版权声明:本文为博主原创文章 && 转载请著名出处 @ http://blog.csdn.net/gatieme https://blog.csdn.net/gatieme/article/details/52402967 日期 内核版

Jsp分页实例---真分页

网页的分页功能的实现比较简单,实现方法也多种多样. 今天总结一个简单的Jsp真分页实例. 首先,提到分页就要先明确一个概念,何为真分页何谓假分页. 假分页:一次性从数据库读出表的所有数据一次性的返回给客户端,由js来控制每一页的显示. 真分页:由程序控制,每一次只返回一页大小的数据,显示到客户端. 由此可以很清楚的分辨出真假分页各自的优缺点: 假分页:由于一次性读出所有数据并返回给客户端,如果数据量庞大,所以这一次的动作可能是非常消耗服务器资源和带宽的, 但是返回给客户端以后就非常轻松了,客户在

SpringMVC分页和搜索分页

分页使我们经常需要使用的功能,昨天在Spring MVC中实现了简单的分页操作和搜索分页,在此记录一下.使用的框架为(MyBatis+SpringMVC+Spring). 首先我们需要一个分页的工具类: 1.分页 import java.io.Serializable; /** * 分页 */ public class Page implements Serializable { private static final long serialVersionUID = -319804844964

如何让IntPtr指向一块内存,以及托管内存与非托管内存的相互转化

IntPtr idp= IntPtr.Zero; StringBuilder idata = new StringBuilder("000000"); string idata ="000000"; 我这样建立的2个idata字符串,如何让idp指向他 我指向他的目的是为了传递给dll的某个函数,他需要传指针 还有我定义了一个结构如何向dll的函数传递其指针? 所有分了,解决一起结了 用GCHandle.Alloc(object obj)方法来给string分配一个

关于php,mysql,html的数字分页和文本分页的两种分页样式供大家参考

请勿盗版,转载请加上出处http://blog.csdn.net/yanlintao1 请勿盗版,转载请加上出处http://blog.csdn.net/yanlintao1 首先进行样式展示希望对大家有所帮助,也希望大家给出意见和建议: 第一种:数字分页 第二种:为文本分页 php分页函数(我写在下面引入的common.inc.php公共文件中): /* *_page()分页的相关参数 *@param int $_pagesize 每页存有几个好友 *@param $_sql 获取所有字段 *

python/Djangof分页与自定义分页

python/Djangof分页与自定义分页 Django分页 1 ##============================================分页======================================================= 2 # current_pagc = request.GET.get('page') 3 # from django.core.paginator import Paginator,Page 4 # # result = m

VB.NET 内存指针和非托管内存的应用

介绍 Visual Basic 从来不像在C或C++里一样灵活的操纵指针和原始内存.然而利用.NET框架中的structures 和 classes,可以做许多类似的事情.它们包括 IntPtr,   Marshal 以及 GCHandle. 这些structures(结构) 和classes(类) 允许你在托管和非托管环境中进行交互.本文中将向您展示如何使用这些structures 和 classes 去完成指针和内存的操作. 关于 IntPtr 结构 IntPtr  结构的行为像一个整型指针