内存管理机制

上传人:ba****u 文档编号:179084416 上传时间:2022-12-30 格式:DOCX 页数:26 大小:36.25KB
收藏 版权申诉 举报 下载
内存管理机制_第1页
第1页 / 共26页
内存管理机制_第2页
第2页 / 共26页
内存管理机制_第3页
第3页 / 共26页
资源描述:

《内存管理机制》由会员分享,可在线阅读,更多相关《内存管理机制(26页珍藏版)》请在装配图网上搜索。

1、在编程中,很多Windows或C+ +的内存函数不知道有什么区别,更别谈有效使用; 根本的原因是,没有清楚的理解操作系统的内存管理机制,本文企图通过简单的总结描述, 结合实例来阐明这个机制。本文目的:对Windows内存管理机制了解清楚,有效的利用C+ +内存函数管理和使用内存。本文内容:本文一共有六节,由于篇幅较多,故按节发表。其他章节请看本人博客的Windows内存管 理及C+ +内存分配实例(一)(二)(三)(四)和(六)。1. 进程地址空间2. 内存状态查询函数3. 内存管理机制-虚拟内存(VM)4. 内存管理机制-内存映射文件(Map)5. 内存管理机制-堆(Heap)使用场合堆是进

2、程创建时在进程空间建立的区域,由堆管理器来管理。一个进程可以有很多个堆。进 程有一个默认堆为1M,可以动态的扩大。当程序需要管理很多小对象时,适合用堆;当需要的空间大于1M时,最好用虚拟内存来管 理。堆的优点是,有堆管理器来替它管理,不需管理具体的事情如页面边界和分配粒度等问题,你可以从调用函数看的出来,比VirtualAlloc的参数少了 不少。堆的缺点是分配和释放的速度比前几种机制要慢,所以最好不要超过1M;不像虚 拟内存那样随时提交和释放,因为它是由堆管理器决定的。如果用堆分配1G的空间,需要1分种,而用虚拟内存,则感觉不到任何延迟。默认堆进程默认堆是供所有线程使用的,每当线程需要从堆中

3、分配释放内存区时,系统会同步堆,所以访问速度较慢。它的默认大小是1M,同样的,你可以通过以下链接命令改变其大小:#pr agma comme nt(l in ker;7HEAP:102400000,1024000)第一个值是堆的保留空间,第二个值是堆开始时提交的物理内存大小。本文将堆改变为 100M。当你在程序中扩大了堆提交的物理内存时,进程运行时,物理内存将减少扩大的数量。但是, 默认堆总是可以扩大的,不能限制它的最大值。当你在程序中扩大了堆保留的空间时,进程运行时,可用进程空间将会减少扩大的数量。每次你用New操作符分配内存时,进程空间会相应的减少,物理内存也会相应的减少。一个重要的提示,

4、本文经过测试,如果你需要的内存块大部分都超过512K,那么,建堆时 给它的初始大小不应该很大,因为,如果你所需内存块大芳12K的话,它不是从堆中分配 的,也就是说不用堆中默认的空间,但其仍然属于堆管理。默认堆的一个用处是系统函数需要利用它运行。比女口,Windows2000的字符集是 UNICODE的,如果调用ANSI版本的函数,系统需要利用堆来从ANSI到UNICODE的 转换,调用UNICODE版本的函数。U 使用场合保护数据结构:将不同的数据结构存在不同的堆中,可以防止不同的结构之间由于指针误操作而破坏了它 们。消除内存碎片:将大小不同的结构保存在一个堆中,会导致碎片的产生,比如释放一个

5、小结构时,大结构也 不能利用它。独享堆的快速:如果用默认堆的话,线程之间是同步访问,速度慢;如果创建独享堆,则系统可以不需同步, 比较快。第二个快速体现在释放的快速,默认堆中,你只能释放某个内存块,而不能释放整个堆;而 独享堆可以一次释放堆,也就是释放了所有的内存块。U 开始使用建立堆:使用以下APIHANDLE HeapCreate(DWORD 选项,SIZE_T 初始大小,SIZE_T 最大 值)“选项”取值为0,不是以下任意一个HEAP_NO_SERIALIZ E,系统无需同步堆HEAP_GENERATE_EXCEPTIONS,当创建失败或分配失败时产生异常。“初始大小”是堆的大小,系统

6、会规整到页面的整数倍,如04096的任何数都为4096;但 是,进程空间至少要64K。“最大值”是堆允许的最大值;为0则无限。使用HEAP_NO_SERIALIZE需确定只有单线程访问这个堆,否则有可能破坏堆;或程序 有同步代码来同步堆。C+程序如下:pHeap=(cha r* )GetP rocessHeap();prin tf(默认堆地址=%xn,pHeap);MEMORYSTATUS memStatus2;GlobalMem or yStatus( &memStatus2);HANDLEhHeap=HeapC reate(HEAP_NO_SERIALIZE|HEAP_GENERATE_E

7、XCEPTIONS,10 24* 1024*50,0);cha r* pHeap=(cha r* )hHeap;prin tf(新建堆 1 地址=%xn,pHeap);if(hHeap= = NULL)cout创建堆失败!endl;MEMORYSTATUS memStatus3;GlobalMem or yStatus( &memStatus3);cout建立堆后:endl;cout减少物理内存=memStatus2.dwAvailPhys-memStatus3.dwAvailPhys e ndl;cout 减 少 可 用 页 文 件 =memStatus2.dwAvailPageFile-m

8、emStatus3.dwAvailPageFileendl;cout 减 少 可 用 进 程 空 间 =memStatus2.dwAvailVirtua卜memStatus3.dwAvailVirtualendlendl;HANDLEhHeap2 = HeapC reate(HEAP_NO_SERIALIZE|HEAP_GENERATE_EXCEPTIONS,1024*1024*10,0);cha r* pHeap2=(cha r* )hHeap2;prin tf(新建堆 2 地址=%xn,pHeap2);结果如下:默认堆地址=1533新建堆丄地址T %豳貓 建立堆后:减少物理包存-527H7

9、328 减少可用瓦文件2584448 减少可芹进程空1=52432896新建堆2地址=4h胡毎貓当建立堆1时,它分配了50M的物理内存给堆使用;当建立堆2时,堆2的地址是0x04bc0000 = 0x019c 0000+50* 1024*1024.使用以下APIPVOID HeapAlloc(HANDLE 堆句柄,DWORD 选项,SIZE_T 字节数)“选项”可以是,HEAP_ZERO_MEMORY,所有字节初始化为0HEAP_NO_SERIALIZE,堆这个内存区独享HEAP_GENERATE_EXCEPTIONS,产生异常。如果创建堆有了它就不用再设了。异常可 能为:STATUS_NO_

10、MEMOR (无足够内存)和 STATUS_ACCESS_VIOLATION (堆被 破坏,分配失败)。C+程序如下:GlobalMem or yStatus(&memStatus3);PVOID pV=HeapAlloc(hHeap,HEAP_ZERO_MEMORY|HEAP_NO_SERIALIZE|HEAP_GENERATE_EXCEPTIONS, 1024*507);if(pV= = NULL)cout分配堆内存失败!endl;char * pC=(char*)pV;prin tf(第一次分配地址=%xn,pC);MEMORYSTATUS memStatus4;GlobalMemo r

11、yStatus( &memStatus4);cout第一次堆分配后:endl;cout减少物理内存=memStatus3.dwAvailPhys-memStatus4.dwAvailPhys e ndl;cout 减 少 可 用 页 文 件 =memStatus3.dwAvailPageFile-memStatus4.dwAvailPageFileendl;cout 减 少 可 用 进 程 空 间 =memStatus3.dwAvailVirtua卜memStatus4.dwAvailVirtualendlendl;PVOID pV2=HeapAlloc(hHeap,HEAP_ZERO_MEM

12、ORY|HEAP_NO_SERIALIZE|HEAP_GENERATE_EXCEPTIONS,1024*508);if(pV2= = NULL)cout分配堆内存失败!endl;cha r * pC2=(cha r* )pV2;prin tf(第二次分配地址=%xn,pC2);MEMORYSTATUS memStatus5;GlobalMem or yStatus( &memStatus5);cout第二次堆分配后:endl;cout减少物理内存=memStatus4.dwAvailPhys-memStatus5.dwAvailPhys e ndl;cout 减 少 可 用 页 文 件 =me

13、mStatus4.dwAvailPageFile-memStatus5.dwAvailPageFileendl;cout 减 少 可 用 进 程 空 间 =memStatus4.dwAvailVirtua卜memStatus5.dwAvailVirtualendlendl;for(int i=0;i 200*1024;i+)pC2i=9;MEMORYSTATUS memStatus10;GlobalMemo ryStatus( &memStatus10);cout第二次堆使用一半后:endl;cout减少物理内存=memStatus5.dwAvailPhys-memStatus10.dwAva

14、ilPhys e ndl;cout 减 少 可 用 页 文 件 =memStatus5.dwAvailPageFile-memStatus10.dwAvailPageFileendl;cout减少可用进程空间=memStatus5.dwAvailVirtua卜memStatuslO.dwAvailVirtualendlendl;结果如下:=0 址后哪件宀宁 地配存文稈 配分费进 八篷理期用次次物可可 一一少少少0 总 2 4 2 S3 GC 4 0 3 2 C 00 5 6 2 - =5:09=s间 址后=4件宀宁 地配存文稈 配分费进 養理用用 次次物可可 二二少少少n 后S0翅 半94通间

15、 一=2件宀宁 畧文稈 使费进 堆遲用用 次物可可 二莎少少可以看出,第一次分配507K的地址为0x04ad d6500x04bc 0000,它是在堆中分 配的;第二次分配508K的地址为0x055c 00200x04bc 0000,它是在堆外分配的;无 论在多大的堆中,只要分配内存块大于507K时,都会在堆外分配,但是,它像在堆中一样, 存在堆的链接表中,受堆管理。分配时,系统使用的是虚拟页文件;只有在真正使用时,才 会分配物理内存。至于为什么分配大于507K会在堆外分配而不直接使用堆中的内存,目前仍然不清楚。改变大小:PVOID HeapReAlloc(HANDLE 堆句柄,DWORD 选

16、项,PVOID 旧内存块地址,SIZE_T 新内存块大小)“选项”除了以上三个外,还有HEAP_REALLOC_IN_PLACE_ONLY,指定不能移动原有内 存块的地址。C+程序如下:GlobalMemo ryStatus(&memStatus4);PVOID pV2New=HeapReAlloc(hHeap,0,pV2,1024*1024*2);if(pV2New! = NULL) cha r * pC2New=(cha r* )pV2New;prin tf(改变分配地址=%xn,pC2New);coutpC2New0endl;/coutpC20endl;出现访问违规SIZE_T lenN

17、 ew=HeapSize(hHeap,0,pV2New);cout改变后大小=lenNewendl;GlobalMem or yStatus( &memStatus5);cout改变分配后:endl;cout减少物理内存=memStatus4.dwAvailPhys-memStatus5.dwAvailPhys e ndl;cout 减 少 可 用 页 文 件 =memStatus4.dwAvailPageFile-memStatus5.dwAvailPageFileendl;cout减少可用进程空间=memStatus4.dwAvailVirtua卜memStatus5.dwAvailVir

18、tualendlendl;结果如下:改变分配地址=56锚沏G改变后大小=2697152改变分配后:減少物理内存=323584 减少可片贝文件-1581856 减少可飪进程空|=15?G96i?可以看出,新内存块紧接着原来内存块结束的地方开始创建,大小为2M;原来的内存块的内 容被销毁和释放,所以新内存块只减少了增加的内存量。一个缺点就是,新内存块居然不保 留原来内存的内容!另外,如果采用HEAP_REALLOC_IN_PLACE_ONLY的话,出现Not Eno ugh Quote异常。也就是说,当前内存的状况是,必须移动才可以扩大此内存块。查询内存:可以查询堆中一个内存块的大小。SIZE_T

19、 HeapSize(HANDLE 堆句柄,DWORD 选项,LPVOID 内存块地 址)“选项”可为0或 HEAP_NO_SERIALIZE。参考以上例子。释放内存块:BOOL HeapFree(HANDLE 堆句柄,DWORD 选项,PVOID 内存块地址)“选项”可为0或 HEAP_NO_SERIALIZE。C+程序如下:GlobalMem or yStatus( &memStatus5);HeapF ree(hHeap,0,pV2New);MEMORYSTATUS memStatus6;GlobalMem or yStatus( &memStatus6);cout第二次堆分配释放后:en

20、dl;cout增加物理内存=memStatus6.dwAvailPhys-memStatus5.dwAvailPhys e ndl;cout 增 加 可 用 页 文 件 =memStatus6.dwAvailPageFile-memStatus5.dwAvailPageFileendl;cout 增 加 可 用 进 程 空 间 =memStatus6.dwAvailVirtua卜memStatus5.dwAvailVirtualendlendl;结果如下:内存空间释放了原来的2M空间。释放堆:BOOL HeapDestroy(HANDLE 堆句柄)不能用它释放默认堆,系统忽略它的处理。这一次,

21、我们先在堆1中分配了70M的内存,由于它很大,所以,堆在堆外给它分配了内存,所以,堆1 一共有50M + 70M = 120M。释放程序如下:PVOIDpV4 = HeapAlloc(hHeap,HEAP_ZERO_MEMORY|HEAP_NO_SERIALIZE|HEAP_GE NERATE_EXCEPTIONS),1024*1024*70);if(pV4= = NULL)cout分配堆内存失败!endl;cha r * pC4=(cha r* )pV4;prin tf(第四次堆分配=%xn,pC4);MEMORYSTATUS memStatus9;GlobalMemo ryStatus(

22、&memStatus9);cout分配堆内存后:endl;cout减少物理内存=memStatus7.dwAvailPhys-memStatus9.dwAvailPhys e ndl;cout 减 少 可 用 页 文 件 =memStatus7.dwAvailPageFile-memStatus9.dwAvailPageFileendl;cout 减 少 可 用 进 程 空 间 =memStatus7.dwAvailVirtua卜memStatus9.dwAvailVirtualendlendl;SIZE_T len = HeapSize(hHeap,0,pV4);coutlen = lene

23、ndl;bool r e=HeapDest ro y(hHeap);if(r e=false)cout释放堆失败!endl;MEMORYSTATUS memStatus8;GlobalMem or yStatus( &memStatus8);cout释放堆后:endl;cout增加物理内存=memStatus8.dwAvailPhys-memStatus9.dwAvailPhys e ndl;cout 增 加 可 用 页 文 件 =memStatus8.dwAvailPageFile-memStatus9.dwAvailPageFileendl;cout 增 加 可 用 进 程 空 间 =me

24、mStatus8.dwAvailVirtua卜memStatus9.dwAvailVirtualendlendl;结果如下:如所猜想一样,释放了 120M内存。获取所有堆:DWORD GetProcessHeaps(DWORD 数量,PHANDLE 句柄数组)“数量”是你想获取的堆数目;“句柄数组”是获得的堆句柄。默认堆也可以获取。HANDLEhan dles10;memset(ha ndles,0,sizeof(ha ndles);GetP rocessHeaps(10,ha ndles);for(int i=0;i10;i+)cout堆i + 1 = handlesiendl;结果如下:堆

25、1=00150000 堆2=00250000 堆3=00260000堆4=詠肾刃孑0陆毎弃 堆5=00390000堆7=019C0B0B堆9=詠肾肾琴拜坯毎弃 堆丄0=3泉瑟00毎肾刃可以看见,一共有8个堆,堆1是默认堆,堆7和堆8是本文建立的堆。另外5个不知来 源。验证堆:BOOL HeapValidate(HANDLE 堆句柄,DWORD 选项,LPVOID 内存块地址)“选项”可为0或 HEAP_NO_SERIALIZE;“内存块地址”为NULL时,验证所有内存块。C+程序如下:HANDLEhan dles10;memset(ha ndles,0,sizeof(ha ndles);Get

26、P rocessHeaps(10,ha ndles);for(int i=0;i10;i+)cout堆i + 1 = handlesi if(HeapValidate(ha ndlesi,O,NULL)cout验证堆成功!endl;elsecoute ndl;结果如下:合并内存块:UINT HeapCompact(HANDLE 堆句柄,DWORD 选项)“选项”可为0或 HEAP_NO_SERIALIZE;此函数可以合并空闲内存块。HeapLock和HeapUnlock通常是系统使用的;HeapWalk可以遍历堆内存,需要以上两个函数。 C+ +内存函数Malloc 和 Free这是C语言使用

27、的函数,只能从默认堆中分配内存,并且只是分配内存,不能调用构造函 数,且只是按字节分配,不能按类型分配。New 和 Delete这是C+语言使用的函数,默认情况下从默认堆中分配内存,但是也可以通过重载New 函数,从自建堆中按类型分配;同时可以执行构造函数和析构函数。它底层是通过HeapAlloc和HeapFree实现的。依赖于编译器的实现。GlobalAlloc 和 GlobalFree这是比HeapAlloc和HeapFree更慢的函数,但是也没有比它们更好的优点,只能在默认 堆中分配;16位操作系统下利用它们分配内存。LocalAlloc 和 LocalFree在 WindowsNT 内

28、核里,和 GlobalAlloc、GlobalFree 是一样的。 一个例子默认情况下,New关键字是利用HeapAlloc在默认堆上建立对象。本文重载了类的New 方法,使得类在自己的堆中存放,这样可以与外面的对象隔离,以免重要的数据结构被意外破坏。由于类中的成员变量是在堆中存放,因此不局限于线程堆栈的1M空间。C+程序如下:class Allocate InO the rHeappublic:Allocate】 nOthe rHeap(void);AllocateI nO the rHeap(void);void * ope rator n ew(size_t size);static H

29、ANDLE heap;public:类对象唯一所需的空间int iArr ay1024*1024*10;Allocatel nO the rHeap:AllocateI nO the rHeap(void)coutAllocate】nOtherHeap()endl;如果New函数没有分配够空间,那么此处会出现访问违规memset(iA rr ay,0,sizeof(Allocate InO the rHeap);iArr ay1024=8;void * Allocate InO the rHeap:ope rat or n ew(size_t size) if(heap= = NULL)hea

30、p=HeapC reate(HEAP_NO_SERIALIZE|HEAP_GENERATE_EXCEPTIONS,1O2 4* 1024*10,0);分配足够这个类对象的空间void * p=HeapAlloc(heap,0,sizeof(AllocateI nO the rHeap);cout堆的大小=HeapSize(heap,O,p)endl;prin tf(AllocateI nO the rHeap 堆地址=%xn,heap);prin tf(AllocateI nO the rHeap 返回地址=%xn,p);return p;AllocateI nO the rHeap:Allo

31、cateI nO the rHeap(void)coutAllocateInOtherHeapendl;void Allocate InO the rHeap:ope rat or delete(void * p)HeapF ree(heap,O,p);HeapDest ro y(heap);coutdelete。endl;;结果如下:=419 43 040列 1 locate InOtherHeapJ1=e aBBSSJlocateInOthepHeapiUilt=18a6020s;ewJ.locatelnOtherHeapO HocatelnOthepHe itp 只寸墓昕在地址=18a820 列 1 locate InOtherHeapjjS弃伤lj 大、=419430堪聃 仃 1 locate I nOtherHeap|j =41943040 il llocatel nOtherHeapde .ete可见,new函数先分配够空间,然后才能初始化对象变量;而delete函数得先做析构,才 能释放空间。对象保存在堆外,因为大于512K;对象大小刚好是iArray变量的大小。注意,如果没有分配足够的空间,虽然你可以得到对象指针,但是你访问数据时可能会出现 访问违规,如果没出现,那更惨,意味着你读写了别人的数据。

展开阅读全文
温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!