编译器可以优化堆内存分配吗?
考虑以下使用 new 运算符分配内存的简单 C 代码:
int main() { int* mem = new int[100]; return 0; }
编译器能否优化新的调用,从而避免动态内存分配?
编译器行为
不同的编译器在这种情况下的行为不同。 g 和 Visual Studio 2015 不会优化新调用,而 clang 会优化,正如在启用完全优化的测试中观察到的那样。
编译器优化原理
根据 N3664 :澄清内存分配,后来成为 C 14 的一部分,允许编译器围绕内存分配进行优化。这种优化是基于新调用没有可观察到的副作用的假设。
As-If 规则
但是,草案中的 as-if 规则C 标准第 1.9 节要求一致的实现来模拟抽象机的可观察行为。从 new 中抛出异常会产生明显的副作用,因此可以认为编译器不允许优化 new 调用。
实现细节
On另一方面,可以说何时从 new 中抛出异常的决定是一个实现细节。 Clang 可能会确定分配不会导致异常,因此在不违反 as-if 规则的情况下忽略新调用。
非抛出分配
使用new 的非抛出版本 new (std::nothrot) int[100] 仍然允许 clang 优化分配。这是因为 clang 可能能够证明不存在可能导致可观察行为的全局替换运算符 new。
积极优化
在 clang 的早期版本中,甚至进行了更积极的优化,如以下代码所示:
#include <cstddef> extern void* operator new(std::size_t n); template<typename T> T* create() { return new T(); } int main() { auto result = 0; for (auto i = 0; i < 1000000; ++i) { result += (create<int>() != nullptr); } return result; }
此代码已优化to:
main: # @main movl 00000, %eax # imm = 0xF4240 ret
实际上,整个循环都被优化掉了。更高版本的 clang 不会执行如此激进的优化。
以上是C 编译器可以优化掉'新”运算符调用吗?的详细内容。更多信息请关注PHP中文网其他相关文章!