windows核心编程13-16 18
来源:互联网 发布:平安证券行情软件下载 编辑:程序博客网 时间:2024/05/22 10:33
用户模式分区:
进程无法通过指针来读取、写入或以任何方式,访问驻留在这一分区中其他进程的数据。对所有应用程序来说,进程的大部分数据都保存在这一分区。由于每个进程都有自己的数据分区,因此一个应用程序破坏另一个应用程序的可能性就非常小,从而使得整个系统更加坚固。
在Windows中,所有.exe和运态链接库都载入到这一区域。每个进程都有可能将这些DLL载入到这一分区内的不同地址(虽然这种可能性很小)。系统同时会把该进程可以访问的所有内存映射文件映射到这一分区。
当应用程序调用VirtualAlloc函数来把物理存储器调拨给地址空间区域时,该空间实际上是从硬盘上的页交换文件分配得到的。
当一个线程试图访问所属进程的地址空间中的一块数据时,有可能会出现两种情况:
第一种情况是,线程要访问的数据就在内存中。在这种情况下,CPU会先把数据的虚拟内存地址映射到内存的物理地址,接下来就可以访问内存中的数据了。
第二种情况是,线程要访问的数据不在内存中,而是位于页交换文件中的某处。在这种情况下,这次不成功的访问被称为页面错误。然后。。。。。。
当用户要求执行一个应用程序时,系统会打开该应用程序对应的.exe文件并计算出应用程序的代码和数据的大小。然后系统会预订一块地址空间,并注明与该区域相关联的物理存储器就是.exe文件本身。是的,系统并没有从页交换文件中分配空间,而是将.exe文件的实际内容(或文件映像,即file image)用作程序预订的地址空间区域。这样一来,不但载入程序非常快,而且页交换文件也可以保持一个合理的大小。
当把一个程序位于硬盘上的文件映像(即一个.exe或DLL文件)用作地址空间区域对应的物理存储器时,我们称这个文件映像为内存映射文件(memory mapped file)。当载入一个.exe或DLL时,系统会自动预订地址空间区域并把文件映像映射到该区域。但是,系统也提供了一组函数,可以让开发人员把数据文件映射到地址空间。
当Windows从软盘载入.exe或DLL文件时,系统会把整个文件从软盘复制到内存中。此外,系统还会从页交换文件中分配足够的存储空间来存放文件映像。只有当系统需要把一个页面换出内存,而页面又包含该文件映像的一部分时,系统才会写入页交换文件。如果系统的内存负载很轻,那么文件总是从内存中直接运行。
我们可以给每个已分配的物理存储页指定不同的页面保护属性。
为了节省磁盘空间,链接器会尽可能地对所生成的PE文件进行压缩。但是,当Windows将PE文件映射到进程的虚拟地址空间时,每一段必须另起一页,而且起始地址必须是系统页面大小的整数倍。这意味着PE文件所需虚拟地址空间的大小一般来说要大于文件本身的大小。
操作系统中有许多值是由系统所运行的主机决定的,如页面大小和分配粒度等。我们绝对不应该在代码中将这些值写死(将这些值硬编码到代码中),而是应该在进程初始化时取得这些值,然后在代码中使用它们。GetSystemInfo函数用来取得与主机相关的值。
GlobalMemoryStatusEx
Windows提供了以下三种机制来对内存进行操控。
虚拟内存:最适合用来管理大型对象数组或大型结构数组。
内存映射文件:最适合用来管理大型数据流(通常是文件),以及在同一机器上运行的多个进程之间共享数据。
堆:最适合用来管理大量的小型对象。
PVOID VirtualAlloc(PVOID pvAddress, SIZE_TdwSize, DWORD fdwAllocationType, DWORD fdwProtext);
Windows认为用MEM_LARGE_PAGE标志分配得到的内存是不可换页的(unpagable):也就是说必须驻留在内存中。这也是为什么以这种方式分配得到的内存能提供更好的性能。但由于内在是稀缺资源,用MEM_LARGE_PAGE标志调用VirtualAlloc需要调用方具有内存中锁定页面的用户权限。
与虚拟内存和内存映射文件相比,堆是用来管理链表和树的最佳方式。堆的优点是它能让我们专心解决手头上的问题,而不必理会分配粒度和页面边界这类的事情。堆的缺点是分配和释放内存块的速度比其他方式慢,而且也无法再对物理存储器的调拨和撤销进行直接控制。
在系统内部,堆就是一块预订的地址空间区域。刚开始,区域内的大部分页面都没有调拨物理存储器。随着我们不断地从堆中分配内存,堆管理器会给堆调拨越来越多的物理存储器。这些物理存储器始终是从页交换文件中分配的。释放堆中的内存块时,堆管理器会撤销已调拨的物理存储器。
进程初始化的时候,系统会在进程的地址空间中创建一个堆。这个堆被称为进程的默认堆。在默认的情况下,这个堆的地址空间区域的大小是1MB。但是,系统可以增大进程的默认堆,使它大于1MB。我们也可以在创建应用程序的时候用/HEAP链接器开关来改变默认的区域大小。由于动态链接库(DLL)没有与之关联的堆,因此在创建DLL的时候不应该使用/HEAP开关。
我们可以通过调用GetProcessHeap来得到进程的默认堆的句柄:
HANDLE GetProcessHeap();
如果始终从堆中分配同样大小的对象,创建多个堆就可以对它们进行更加有效的管理。
快速释放。把一些数据结构存入在一个专门的堆中还有另一个好处,即我们可以直接释放整个堆而不必显示地释放堆中的每个内存块。
HANDLE HeapCreate(DWORD fdwOptions, SIZE_TdwInitialSize, SIZE_T dwMaximumSize);
如果想在堆中存放可执行代码,则必须使用标志HEAP_CREATE_ENABLE_EXECUTE。这对“数据执行保护”这项特性来说特别重要。如果不设置这个标志,那么当我们试图在来自堆的内存块中执行代码时,系统会抛出EXCEPTION_ACCESS_VIOLATION异常。
HeapCreate的第2个参数表示一开始要调拨给堆的字节数。如果需要,HeapCreate会把这个值向上取整到CPU页面大小的整数倍。最后一个参数dwMaximumSize表示堆所能增长到的最大大小。如果dwMaximumSize为0,那么创建的堆将是可增长的,它没有一个指定上限,从堆中分配内存会使堆不断增长,直到用尽所有的物理存储器为止。
PVOID HeapAlloc(HANDLE hHeap, DWORDfdwFlags, SIZE_T dwBytes);
第1个参数hHeap是一个堆的句柄,表示要从哪个堆中分配内存。参数dwBytes表示要从堆中分配多少个字节。中间的参数fdwFlags用来指定一些标志,这些标志会对分配产生影响。目前,系统只支持3个标志:HEAP_ZERO_MEMORY, HEAP_GENERATE_EXCEPTIONS和HEAP_NO_SERIALIZE。
PVOID HeapReAlloc(HANDLE hHeap, DWORDfdwFlags, PVOID pvMem, SIZE_T dwBytes);
如果一个内存块是链表或树的一部分,则需要指定HEAP_REALLOC_IN_PLACE_ONLY标志。在这种情况下,链表或树中的其他节点可能包含指向当前节点的指针,把节点移动到堆中其他的地方会破坏链表或树的完整性。
分配一块内存后,可以调用HeapSize函数来得到这块内存的实际大小。
SIZE_T HeapSize(HANDLE hHeap, DWORDfdwFlags, LPCVOID pvMem);
BOOL HeapFree(HANDLE hHeap, fdwFlags, PVOIDpvMem);
BOOL HeapDestroy(HANDLE hHeap);调用HeapDestroy会释放堆中包含的所有内存块,同时系统会收回堆所占用的物理存储器和地址空间区域。
CSomeClass * pSomeClass = new CSomeClass();
C++编译器编译这一行代码的时候,它会首先检查CSomeClass是否包含一个重载的new操作符的成员函数。如果找到,编译器将生成代码来调用这个成员函数。如果编译器无法找到哪个函数重载了new操作,编译器将生成代码来调用C++的标准new操作符。
通过对C++类的new和delete操作符进行重载,我们可以非常容易地将堆函数加以运用。
- windows核心编程13-16 18
- windows核心编程18
- windows核心编程13
- windows核心编程16
- 读Windows核心编程 - 13
- 【Windows 核心编程】Windows 核心编程 -- 进程
- 【Windows核心编程】Windows核心编程 -- 作业
- windows 核心编程之18 堆
- windows核心编程 第18章 堆
- WINDOWS核心编程笔记(16-21)
- Windows核心编程(三)
- windows核心编程--字符集
- windows核心编程--进程
- windows核心编程--作业
- windows核心编程--线程
- windows核心编程--纤程
- windows核心编程--精华
- windows核心编程--纤程
- Java实现有序单向链表
- oracle表分区详解
- EXTJS笔记整理1
- 一、C++相关知识简介
- 巧用浏览器开发人员工具和扩展下载网络视频
- windows核心编程13-16 18
- 华三H3C E5200与E2100组建IPSEC VPN
- sqlite
- 图解:光缆终端盒、尾纤的作用和接法
- Ogre compile error
- Cocos2D-x 2.0以上版本跨Android开发环境的搭建---------------------cocos2d-x 3.0正式版本(7.2)
- 写在《嵌入式Linux驱动模板精讲与项目实践》上市之后
- 通过JDK proxy创建动态类,并查看其方法列表信息
- 分布式nagios的配置