第十六章:线程栈

1:基础

1:线程初始化时,线程栈默认1M,所有页面都是PAGE_READWRITE属性,但只为前两个页面调拨了物理存储器,地址低的那个页面叫防护页面,为其指定了PAGE_GUARD属性

2:当线程访问到防护页面时,由于指定了PAGE_GUARD属性,系统会得到通知,系统会为防护页面的下一个页面调拨物理存储器,并指定PAGE_GUARD属性,使之成为新的防护页面,同时,系统去除原来防护页面的PAGE_GUARD属性

3:当防护页面为倒数第三个页面时,如果线程继续访问,会为倒数第二个页面调拨物理存储器,但是并不为其指定PAGE_GUARD属性,当线程访问到此页面时,会触发EXCEPTION_STACK_OVERFLOW异常,如果应用程序忽略该异常,继续访问最后一个页面,由于未调拨物理存储器,则产生访问违规异常,操作系统会终止进程

2:栈下溢

char szBuf[100];
szBuf[10000]='a';

从基础可以看出,当前时刻,肯定有两个页面已经调拨了物理存储器,所以如szBuf[3000]='a',编译器也不会报错,但如上代码,赋值的地址已经超过了两个页面,这就是所谓的栈下溢

操作系统不一定能检测出栈下溢,因为下溢访问的地方,也许我们已经为其调拨了物理存储器

3:C/C++运行库栈检查函数

如果在栈上定义int a[4000],操作系统实际上只是把栈指针下移8000个字节,并没有为其调拨物理存储器,只有真正访问时才调拨,但操作系统这样的实现是有问题的,因为如果有a[0]=0这样的操作,便会引起访问违规(我的理解:因为这个时候栈指针指向很远的地方,只能在那里调拨物理存储器),为了解决这个问题,编译器做了些工作,当编译器处理每个函数的时候,会算出函数要多大的栈空间,如果栈空间大于目标系统的页面大小,编译器会调用栈检查函数,栈检查函数会去访问该函数所需空间的每个页面,从高地址向低地址,每个页面写入一个字节的值,这样,系统会慢慢扩大线程栈的大小,为经过的每个页面调拨物理存储器

4:以后学习下编译器一些栈安全性检查

5:一个重点

当线程堆栈溢出时,如在[基础]中所说,会抛出EXCEPTION_STACK_OVERFLOW异常,如果我们用SEH完美的处理了此问题,当此线程下次再溢出时,就不能够抛出此异常了,因为除最后一个页面之外的所有页面已经调拨了物理存储器,系统取而代之的是抛出访问违规

这里有两个重点:

(1):如果想让线程下次溢出还能抛出异常,需调用C运行库_resetkoflw函数

(2):系统为线程栈调拨了物理存储器,即使线程栈指针又移到了高地址,系统也不会去释放这些调拨的物理存储器,因为线程栈的使用时非常频繁的,频繁的申请释放没有意义

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值