Visual Studio C++编译器选项:为什么/ O2定义/ Gs?

Joh*_*åde 16 c++ visual-studio

Visual Studio C++编译器选项/ O2(最大化速度)相当于

/Og /Oi /Ot /Oy /Ob2 /Gs /GF /Gy
Run Code Online (Sandbox Code Playgroud)

为什么/ Gs?它如何帮助最大化速度?(注意它是/ Gs,而不是/ GS.)

MSa*_*ers 13

/ Gs将在使用多个页面(通常为4kB)局部变量的函数中插入堆栈探测器.堆栈探测器向操作系统发出信号,告知您将使用大量堆栈空间.如果此探测器到达保护页面,则操作系统知道它将需要为堆栈分配额外的RAM页面来增长.

这是一种优化,因为没有探测器,实际的存储器访问将触发RAM分配,并且该功能将停止,直到分配RAM为止.作为函数序言的一部分,探针不会导致失速(至少不会那么严重).

[edit]另一个好处是前面的堆栈探测将分配一次内存.如果您需要16 KB的堆栈空间并依赖按需分配,那么您将有4个页面错误,每个错误会使堆栈增加4 KB.单个探头可以用一个系统调用替换这4个故障.


Gle*_*les 2

/O2 没有设置 /Gs,这是文档中的错误。

一些实验(很容易在生成的程序集中看到 __chkstk 调用)表明:

/Gs(没有数字)相当于 /Gs0,意味着始终插入 __chkstk 调用。事实上,MSDN 也这么说:

如果指定 /Gs 选项时没有指定大小参数,则与指定 /Gs0 相同,

/O2 不设置/Gs(又名 /Gs0),“/O2”和“/O2 /Gs”之间有明显的区别。尽管它有可能将默认值更改为页面以外的其他内容,但这似乎更有可能只是一个文档错误。

堆栈探针永远不会有利于性能,它只在堆栈前进到新的高水位线时才起作用,并且在其余时间中被浪费循环。这意味着,如果您有一个调用函数 100 次的循环,则该函数堆栈探测可能会在第一次增加堆栈,但其他 99 次它不会改变任何内容,因为堆栈已经在第一次增加 - 如果需要的话完全成长。