Windows内存管理机制
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Windows内存管理机制
在编程中,很多Windows或C++的内存函数不知道有什么区别,更别谈有效使用;根本的原因是,没有清楚的理解操作系统的内存管理机制,本文企图通过简单的总结描述,结合实例来阐明这个机制。
本文目的:
对Windows内存管理机制了解清楚,有效的利用C++内存函数管理和使用内存。
本文内容:
本文一共有六节,由于篇幅较多,故按节发表。其他章节请看本人博客的Windows内存管理及C++内存分配实例(一)(二)(三)(四)和(五)。
1. 进程地址空间
2.内存状态查询函数
3.内存管理机制--虚拟内存 (VM)
4.内存管理机制--内存映射文件 (Map)
5.内存管理机制--堆 (Heap)
使用场合
操作系统为每个线程都建立一个默认堆栈,大小为1M。这个堆栈是供函数调用时使用,线程内函数里的各种静态变量都是从这个默认堆栈里分配的。
堆栈结构
默认1M的线程堆栈空间的结构举例如下,其中,基地址为0x0004 0000,刚开始时,CPU的堆栈指针寄存器保存的是栈顶的第一个页面地址
0x0013 F000。第二页面为保护页面。这两页是已经分配物理存储器的可用页面。
随着函数的调用,系统将需要更多的页面,假设需要另外5页,则给这5页提交内存,删除原来页面的保护页面属性,最后一页赋予保护页面属性。
当分配倒数第二页0x0004 1000时,系统不再将保护属性赋予它,相反,它会产生堆栈溢出异常STATUS_STACK_OVERFLOW,如果程序没有处理它,则线程将退出。最后一页始终处于保留状态,也就是说可用堆栈数是没有1M的,之所以不用,是防止线程破坏栈底下面的内存(通过违规访问异常达到目的)。
当程序的函数里分配了临时变量时,编译器把堆栈指针递减相应的页数目,堆栈指针始终都是一个页面的整数倍。所以,当编译器发现堆栈指针位于保护页面之下时,会插入堆栈检查函数,改变堆栈指针及保护页面。
这样,当程序运行时,就会分配物理内存,而不会出现访问违规。
使用例子
改变堆栈默认大小:
有两个方法,一是在CreateThread()时传一个参数进去改变;
二是通过链接命令:
#pragma comment(linker,"/STACK:102400000,1024000")
第一个值是堆栈的保留空间,第二个值是堆栈开始时提交的物理内存大小。本文将堆栈改变为100M。
堆栈溢出处理:
如果出现堆栈异常不处理,则导致线程终止;如果你只做了一般处理,内存
结构已经处于破坏状态,因为已经没有保护页面,系统没有办法再抛出堆栈溢
出异常,这样的话,当再次出现溢出时,会出现访问违规操作
STATUS_ACCESS_VIOLATION,这是线程将被系统终止。解决办法是,恢复
堆栈的保护页面。请看以下例子:
C++程序如下:
bool handle=true;
static MEMORY_BASIC_INFORMATION mi; LPBYTE lpPage;
//得到堆栈指针寄存器里的值
_asm mov lpPage, esp;
// 得到当前堆栈的一些信息
VirtualQuery(lpPage, &mi, sizeof(mi));
//输出堆栈指针
printf("堆栈指针=%x\n",lpPage);
// 这里是堆栈的提交大小
printf("已用堆栈大小=%d\n",mi.RegionSize); printf("堆栈基址=%x\n",mi.AllocationBase);
for(int i=0;i<2;i++)
{
__try
{
__try
{
__try
{
cout<<"**************************"< //如果是这样静态分配导致的堆栈异常,系统默认不 抛出异常,捕获不到 //char a[1024*1024]; //动态分配栈空间,有系统调用Alloca实现,自动 释放 Add(1000); //系统可以捕获违规访问 int * p=(int*)0xC00000000; *p=3; cout<<"执行结束"< } __except(GetExceptionCode()==STATUS_ACCESS_ VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { cout<<"Excpetion 1"< } } __except(GetExceptionCode()==STATUS_STACK_OVERFL OW ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { cout<<"Exception 2"< if(handle) { //做堆栈破坏状态恢复 LPBYTE lpPage; static SYSTEM_INFO si; static MEMORY_BASIC_INFORMATION mi; static DWORD dwOldProtect; // 得到内存属性 GetSystemInfo(&si); // 得到堆栈指针 _asm mov lpPage, esp; // 查询堆栈信息 VirtualQuery(lpPage, &mi, sizeof(mi)); printf("坏堆栈指针=%x\n",lpPage);