Windows 内存的分配

news/2024/11/9 22:16:40

转载  Windows 内存的分配 收藏

 

Windows 使用一种  分页请求虚拟内存系统,现在我们就来分析一下这种系统。  虚拟地址空间
虚拟内存的概念在上个世纪五十年代就提出了,当时是作为解决不能一次装入实际内存的程序这一复杂问题的方案提出的。在虚拟内存系统中,程序可以访问超出可用物理内存的更大的地址集合,专用内存管理程序将这些逻辑地址映射到实际地址,使用磁盘上的临时存储保存超出的部分。
Windows 所使用的现代虚拟内存实现中,虚拟存储被组织成大小相同的单位,称为  。每个操作系统进程占用自己的  虚拟地址空间,即一组可以读写的虚拟内存页。每个页可以有三种状态: 
  • 自由:还没有进程使用这部分地址空间。如果企图访问这部分空间,无论读写都会造成某种运行时失效。该操作将导致弹出一个 Windows 对话框,提示出现了访问冲突。(Java 程序不会造成这种错误,只有用支持指针的语言编写的程序才可能造成这种问题。)
  • 保留:这部分地址空间保留给进程,以供将来使用,但是在交付之前,不能访问该地址空间。很多 Java 堆在一开始处于保留状态。
  • 提交:程序可以访问的内存,得到了完全 支持,就是说已经在分页文件中分配了页帧。提交的页只有在第一次被引用时才装入主存,因此成为 请求式分页
图 1 说明了进程地址空间中的虚拟页如何映射到内存中的物理页帧。

图 1. 进程地址空间中的虚拟页到物理页帧的映射
 
如果运行的是 32 位机器(如一般的 Intel 处理器),那么进程的整个虚拟地址空间就是 4GB,因为这是用 32 位所能寻址的最大地址空间。Windows 通常不会允许您访问地址空间中的所有这些内存,进程自己使用的只有不到一半,其他供 Windows 使用
内存管理之二

Virtual Address Space (虚拟地址空间)

虚拟地址表示的是进程中非实际物理地址的位置。换句话说就是,系统为每个进程维护着一个页面映射,这个页面映射是一个内部的数据结构,它的作用是将虚拟地址转换为相应的物理地址。
虚拟地址空间分为以下几部分:
Windows NT 4.0 SP3 Server Enterprise Edition, Windows 2000 Advanced Server, and Windows .NET Enterprise Server:一般的,进程能够使用低端的3GB空间(0x00000000 0xBFFFFFFF)。高端的1GB内存(0xC0000000  0xFFFFFFFF)为系统保留部分。
Windows NT/2000/XP:进程能够使用低端的2GB内存(0x00000000  0x7FFFFFFF),高端的2GB内存(0x80000000  0xFFFFFFFF)系统保留。
Windows 95/98/Me:对应描述如下表
区间
用途
0K - ~64K (0xFFFF)
不可写。这块区域大约应是为系统装载一些MSDOS的特性而保留的。这块内存对于进程而言是私有的。
~64K (0x10000) - 
4 MB (0x3FFFFF) 
为兼容MS-DOS保留。这块内存对进程而言可读可写。然而,这段区域有可能保存着一些MSDOS相关的结构或代码,所以进程不应该在这段区域随意读出或写入。这块内存对于进程而言是私有的。
4MB (0x400000) - 
2GB (0x7FFFFFFF) 
用于代码和用户数据。用户数据可读可写。代码是只执行的。这块内存对进程而言是私有的。
2GB (0x80000000) - 
3GB (0xBFFFFFFF) 
共享区。对于所有进程都可读写。一些系统的动态连接库和其它一些数据装载到这段区域。
3GB (0xC0000000) - 
4GB (0xFFFFFFFF) 
系统内存。对任意进程都是可读可写。然而,需要注意的是,这段内存是保存低等级的系统代码的地方,所以,向这片区域写入数据可能会破坏系统可能造成灾难性后果。.

详情请参阅MSDN
  • Virtual Address Space and Physical Storage   Page State
  • Scope of Allocated Memory
  1. 内存管理之三

    Virtual Memory Functions( 虚拟内存函数族 )
           此族函数用于进程操作或决定虚拟内存地址空间中页面的状态。他们可以实现以下一些操作:
    1、   预留一个虚拟地址空间的区域。预留的地址空间不占用任何的实际物理内存,但是会防止其它分配操作在此范围内分配内存。它不会影响其它进程的虚拟地址空间。当进程需要把一个动态增长的数据结构分配在一个预留的内存空间中时,预留内存操作避免不必要的物理内存占用。进程在需要时能够为这块空间分配物理内存。
    2、   将进程虚拟地址空间预留页的范围提交给进程,这样,这片物理存储区(不论是内存还是磁盘)只能被此进程访问。
    3、   描述已提交页面区域的读/写、只读、拒绝访问等属性。不同于标准的分配函数的地方是它分配的页面总有 / 属性。
    4、   释放已预留的内存区域。使这片虚拟内存区域对于调用进程后来的分配操作处于可用状态。
    5、   把已提交页面区域解除提交。释放对应的物理存储区,使之对于后来的任意进程的分配操作有效。
    6、   锁定一页或更多已提交页到物理内存中,使这些被锁定页面不回被系统交换到页面文件中。
    7、   获得关于调用进程或指定进程虚拟地址空间某一区域之内已提交页面的资料。
    8、   改变调用进程或指定进程虚拟地址空间指定区域已提交页面的访问限制级。
    内存管理之四

    Allocating Virtual Memory  (分配虚拟内存)
    虚拟内存函数用于操作内存页面。这些函数用当前机器上的页面的大小来实现描述内存的大小和地址的功能。
           VirtualAlloc 函数执行以下的操作中的一个:
    1、   预留一页或多页的自由页面。
    2、   提交一页或多页预留页面。
    3、   预留和提交一页或多页自由页面。
    你可以指定你要预留或提交页面的起始地址,或者你也可以让系统来决定这个地址。函数将指定的地址调整到适当的页面边界。预留页面是不允许访问的,但已提交的页面可以被以页读/写、页只读、页访问禁止等访问规则进行分配。当页面被提交之后,在页面文件中就分配了存储区,但所有页面都只是在第一次试图读或写该页面的时候被调入物理内存。你可以用一般指针来访问用VirtualAlloc函数提交的内存。

    Freeing Virtual Memory  (释放虚拟内存)
    VirtualFree函数执行以下操作中的一个:
    1、   取消提交一个或更多的已提交页面,把页面状态切换到预留。取消提交的页面将释放于该页面相关联的物理存储区,使这片区域能够被任意进程重新使用。所有被提交的页面块都可以被取消提交。
    2、   释放一片包含一个或多个预留页面的内存块,把页面状态切换到空闲。已释放的页面块能够被该进程重新使用。被预留页面只能够一次释放全部的之前使用VirtualAlloc函数预留的块。
    3、   同时取消提交和释放一个包含一个或多个页面的块,将这些页面的状态切换为空闲。指定的块必须包含全部之前使用VirtualAlloc函数预留的块,而且通常所有这些页面已经被提交。
           当一个内存块被释放或者取消提交之后,你就不能再引用它。所有之前在其中的信息都永远消失。试图在一个空闲页面上执行读写操作会导致一个访问违例。如果你还需要这些某些信息,那么请不要取消提交或者释放包含这些资料的内存。
           如果想要说明某片内存区域的数据不再游泳,那么在调用VirtualAlloc时使用MEM_RESET参数。这样这些页面上的数据将不会在读取或写入页面文件。然而,这块内存仍可再次被使用。
    Working With Pages   (页面操作)
           使用GetSystemInfo函数能够得到当前机器的页面大小。
           VirtualQuery VirtualQuerayEx函数能够返回关于 某一进程的地址空间中始于指定地址的连续的页面空间 的资料。VirtualQuery返回关于调用进程的内存资料。VirtualQueryEx返回关于指定进程的内存资料而且通常能够支持需要处于调试态进程资料的调试器。页面区域会被限制在 向下调整到最近页面边界的指定地址上。一直延伸到所有拥有以下共同特性的后续页面:
    1、   所有页面状态一致:是已提交或预留或空闲三状态之一。
    2、   如果起始页面非空闲,那么所有该区域页面都是被VirtualAlloc一起初始化的内存页面组的一部分。
    3、   所有页面访问控制级都一致:是 页只读、页读写、页禁止访问三级之一。
    VirtualLock函数使进程能够锁定一页或多页已提交内存进入物理内存(RAM,防止系统将这些页面交换到页面文件中。它能够被用于确保在不进行磁盘访问的情况下使临界数据可访问。锁定页面进内存是危险的,这是因为它会限制系统管理内存的能力。的使用VirtualLock函数能够导致可执行代码被交换到页面文件从而降低系统性能。VirtualUnlock函数将被VirtualLock锁定的内存解锁。
    VirtualProtect函数能够调整所有在进程地址空间中的已提交页面的访问限制级。比如,进程可以分配读写页面来存储常变数据,并且之后它能够把访问控制级改变为只读或者禁止访问来防止以外的改写。VirtualProtect是一个用VirtualAlloc分配的页面上的典型的应用,但是,它也能够应用于使用其它分配函数分配的页面上。然而,VirtualProtect改变了全部页面的保护级,但是其它分配函数返回的指针并不一定要页面对齐。VirtualProtectEx函数类似于VirtualProtect函数,除了它只改变指定进程内存的限制级之外。改变限制级在调试器访问被调试进程的内存的时候会很有用处。
    内存管理之五

    Memory Management Functions  (内存管理函数)
    以下的函数用于内存管理
    函数
    描述
    CopyMemory
    将一块内存从位置拷贝到另外一个位置
    FillMemory
    将指定内存块内容填充为指定数据
    GetWriteWatch
    查找已经被写入虚拟内存区域的页面地址
    GlobalMemoryStatus
    获得关于系统当前对于物理内存和虚拟的内存的使用信息。
    GlobalMemoryStatusEx
    获得关于系统当前对于物理内存和虚拟的内存的使用信息。
    IsBadCodePtr
    决定调用进程是否拥有对指定地址内存的读操作权。

    IsBadReadPtr
    检验调用进程是否拥有对指定内存范围的读操作权。

    IsBadStringPtr
    检验调用进程是否拥有对指定字符串所在地址区域的读操作权。

    IsBadWritePtr
    检验调用进程是否拥有对指定内存范围的写操作权。

    MoveMemory
    将一块内存从一个位置移动到另外的位置。

    ResetWriteWatch
    为某片虚拟内存区域重置写跟踪状态。

    ZeroMemory
    用零值填充某片内存块。


    以下是 AWE(Address Windowing Extensions) 函数
    函数
    描述
    AllocateUserPhysicalPages
    分配物理内存页面与进程的AWE区域建立或取消映射


    FreeUserPhysicalPages
    释放先前由AllocateUserPhysicalPages函数分配的物理内存页面。

    MapUserPhysicalPages
    映射在AWE区域内的指定地址分配的物理内存。

    MapUserPhysicalPagesScatter
    同上


    以下的函数是全局(global)和本地(local)函数。这类函数运行速度较之其它内存管理函数为慢并且有很多特性没有提供。这就是说,新的应用程序应该尽量使用堆函数(heap functions).然而,全局函数(global functions)仍然被用在DDE和剪贴板操作中。
    函数
    描述
    GlobalAlloc
    从堆中分配指定字节数量的内存。

    GlobalDiscard
    丢弃指定的全局内存块

    GlobalFlags
    返回关于指定全局内存对象的信息

    GlobalFree
    释放指定的全局内存对象。

    GlobalHandle
    返回指定全局内存块的指针的句柄。

    GlobalLock
    锁定一个全局内存对象并且返回指向该内存块第一个字节的指针。

    GlobalReAlloc
    改变指定全局内存对象的大小和属性。

    GlobalSize
    得到指定内存对象的当前大小。

    GlobalUnlock
    减少对一个内存对象的锁定数量。

    LocalAlloc
    从堆中分配指定数量的内存。

    LocalDiscard
    丢弃指定的本地内存对象

    LocalFlags
    返回关于指定本地内存对象的信息。

    LocalFree
    释放指定的本地内存对象。

    LocalHandle
    得到指向指定本地内存对象的指针的句柄。

    LocalLock
    锁定本地内存对象并且返回指向该内存对象的第一个字节的指针。

    LocalReAlloc
    改变指定本地内存对象的大小或者属性。

    LocalSize
    返回指定本地内存对象的当前大小。

    LocalUnlock
    减少对某内存对象的锁定数量。


    以下是堆函数族。
    函数
    描述
    GetProcessHeap
    获得调用进程的堆的一个句柄。

    GetProcessHeaps
    获得调用进程所有有效的堆的句柄。

    HeapAlloc
    从堆中分配一块内存

    HeapCompact
    尝试压紧指定的堆。

    HeapCreate
    创建一个堆对象。

    HeapDestroy
    销毁指定的堆对象。

    HeapFree
    释放一块从堆中分配的内存。

    HeapLock
    尝试获得与指定堆关联的锁定。

    HeapQueryInformation
    获得关于指定堆的资料。

    HeapReAlloc
    从堆中重新分配一块内存。

    HeapSetInformation
    为指定的堆设置堆信息。

    HeapSize
    获得一个在堆上的内存块的大小。

    HeapUnlock
    获得与指定堆相关联的一个锁定的所有者。

    HeapValidate
    尝试使指定的堆有效。

    HeapWalk
    枚举指定堆上的内存块。


    以下是虚拟内存函数。
    函数
    描述
    VirtualAlloc
    保留或提交调用进程虚拟地址空间的某一区域的页面。

    VirtualAllocEx
    保留或提交调用进程虚拟地址空间的某一区域的页面。

    VirtualFree
    释放或取消提交调用进程虚拟地址空间的某一区域的页面。

    VirtualFreeEx
    释放或取消提交调用进程虚拟地址空间的某一区域的页面。

    VirtualLock
    锁定指定的进程虚拟地址空间的指定块到物理内存中。

    VirtualProtect
    改变调用进程虚拟地址空间已提交页面区域的访问限制级。

    VirtualProtectEx
    改变调用进程虚拟地址空间已提交页面区域的访问限制级。

    VirtualQuery
    提供关于调用进程虚拟地址空间页面区域的资料。

    VirtualQueryEx
    提供关于调用进程虚拟地址空间页面区域的资料。

    VirtualUnlock
    对某进程虚拟地址空间的某区域的页面解锁


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

相关文章

Silverlight开发历程—(利用Image.OpacityMask做透明遮罩)

文本画刷ImageBrush 用文本画刷&#xff0c;可以填充一些图形&#xff0c;文字的背景&#xff0c;例如下面代码&#xff0c;利用ImageBrush填充字体的背景。 <Canvas x:Name"LayoutRoot" Background"AliceBlue"> <TextBlock Text"ImageBr…

Linux中断内核编程

Linux中断内核编程 前言 在前面分析了中断的基本原理后&#xff0c;就可以写一个内核中断程序来体验以下&#xff0c;也可以借此程序继续深入来了解内核中断的执行过程 一.内核中断程序 &#xff1a; 我们还是来看一看成程序&#xff1a; 在看程序之前&#xff0c;要熟悉如…

Silverlight开发历程—(Clip裁剪特效)

Clip裁剪特效 裁剪特效&#xff08;Clip&#xff09;&#xff0c;允许对Silverlight元素进行裁剪&#xff0c;裁剪形状由Clip属性内包含的Geometry决定&#xff0c;下面直接上代码&#xff1a; <StackPanel x:Name"LayoutRoot" Orientation"Horizontal"…

configure文件中的build、host、target含义

configure文件中的build、host、target含义 今天阅读autobook[注1]一书,3.4节讲到了configuration name。书中提到了build、host、target这几个变量。看起来容易让人感到一些混淆&#xff0c;其实这极大的简化了二进制文件格式生成的控制。build -- 在build系统中建…

Android手机快捷键大全

Android手机快捷键大全 Posted by IA on 2010 年 12 月 24 日 Android手机的市场份额是越来越大&#xff0c;Android手机新用户也是越来越多&#xff0c;下面让我们来学习一下Android手机的快捷键&#xff0c;不管新手还是老手总会对你有用的! 全局快捷键启动&#xff08;默认&…

linux应用层获取鼠标坐标

linux应用层获取鼠标坐标2011-01-13 22:46补充&#xff1a;在这个函数中要打开一个鼠标设备&#xff0c;但是在嵌入式的文件系统中没有这个设备节点&#xff0c;鼠标设备的主设备号和次设备号有是如何确定的呢&#xff1f;在 linux 系统中&#xff0c;鼠标和键盘的设备号都是固…

makefile解释及模板

调试makefile 收藏一个调试makefile文件的简便方法&#xff1a;那就是用make -p|tee make.out来输出make运行过程中产生的中间信息。make -n 就可以输出调试make 的运行——————一般来说&#xff0c;最简单的就是直接在命令行下输入make命令&#xff0c;make命令会找当前目…

miniGui开发进展解决

1.miniGUI中&#xff0c;可以在编译配置选项中设置UI风格。改为FLAT后&#xff0c;编译示例报错。说是myDrawButton没有定义。后来看了源码&#xff0c;才解决。原来定义FLAT时&#xff0c;还有个_GRAY_SCREEN宏开关&#xff0c;决定是否定义&#xff4d;&#xff59;&#xff…