当系统创建线程时,会为线程栈预订一块地址区域(从进程地址空间区域)(每个线程都有自己的线程栈),并调拨一些物理存储器。默认情况是2MB的地址区域,并调拨2个页面的存储器:区域最顶部的(地址最高)的两个页面。
在线程执行之前,栈指针指向顶部第一个页面的尾部,这个页面就是线程开始执行使用栈的地方,第二个页面成为防护页面。随着线程调用越来越多的函数,需要的线程栈需要也越来越多。因此,“当前页面”和“防护页面”随着需要而下移。如图:
当线程试图调用防护页面时,系统会为防护页面下面的一个页面调拨物理存储器,并设为防护页面。该技术使得系统在真正需要的时候才增大线程栈的存储器大小。如图:
当系统给最后第二个调拨物理存储器时会引发一个栈溢出的异常(栈底最后一个页面始终不会被调拨物理存储器,即不会被使用,这是为了隔离(否则如果线程栈空间不断需要增大,那么可能占用0x800000000以下的已经被其他占用的空间,进行改写,造成难以扑捉的问题!))。因此如果此时继续使用线程栈,就会引发整个进程终止——而不仅是当前线程。