为什么我的C++编译器不优化这些内存写入?
Why doesn't my C++ compiler optimize these memory writes away?
我创建了这个程序。除了使用处理能力之外,它没有做任何有趣的事情。
查看objdump -d
的输出,即使在使用O3编译时,我也可以看到三个rand
调用和相应的mov
指令接近末尾。
为什么编译器没有意识到内存不会被使用,只是用while(1){}
替换下半部分?我正在使用gcc
,但我最感兴趣的是标准的要求。
/*
* Create a program that does nothing except slow down the computer.
*/
#include <cstdlib>
#include <unistd.h>
int getRand(int max) {
return rand() % max;
}
int main() {
for (int thread = 0; thread < 5; thread++) {
fork();
}
int len = 1000;
int *garbage = (int*)malloc(sizeof(int)*len);
for (int x = 0; x < len; x++) {
garbage[x] = x;
}
while (true) {
garbage[getRand(len)] = garbage[getRand(len)] - garbage[getRand(len)];
}
}
因为GCC不够聪明,无法在动态分配的内存上执行此优化。但是,如果您将garbage
改为本地数组,GCC将循环编译为:
.L4:
call rand
call rand
call rand
jmp .L4
这只是重复调用rand
(这是必需的,因为调用有副作用),但优化了读取和写入。
如果GCC更聪明,它也可以优化rand
调用,因为它的副作用只影响后来的rand
调用,而在这种情况下没有任何副作用。然而,这种优化可能会浪费编译器编写者的时间。
一般来说,它不能告诉rand()
在这里没有可观察到的副作用,并且不需要删除这些调用。
它可以删除写操作,但可能使用数组就足以抑制写操作。
标准既不要求也不禁止它正在做的事情。只要程序具有正确的可观察行为,任何优化都纯粹是实现质量问题。
这段代码导致未定义行为,因为它有一个没有可观察行为的无限循环。因此任何结果都是允许的。
在c++ 14中,文本是1.10/27:
实现可以假设任何线程最终将执行以下操作之一:
- 终止,
- 调用库I/O函数,
- 访问或修改易失性对象,或
- 执行同步操作或原子操作。
[注:这是为了允许编译器转换,比如删除空循环,即使不能证明终止。-end note]
我不会说rand()
算作I/O函数。
相关的问题
让它有机会因数组溢出而崩溃!编译器不会推测getRand
的输出范围
相关文章:
- 对于堆上的页面对齐内存分配是否有任何优化或不同的 API?
- C++二和.优化内存使用
- 如何控制或优化或删除或释放 UNION 中未使用的内存
- 如果 RMW 操作没有任何变化,是否可以针对所有内存顺序对其进行优化
- std::stable_sort: 如何选择内存优化算法而不是时间优化算法?
- 字符串编码用于内存优化
- 编译器内存优化 - 重用现有块
- 编译器是否优化析构函数中的内存集
- 矢量函数的C 内存优化
- 如何在CPU和内存中优化C 中的重型地图插入
- C++对间接运算符的标准描述是否保证内存写入不会被优化掉
- 内存分配,用于在C 11中循环中函数的返回值:如何优化
- 编译器优化了内存分配
- C++字符串内存重用优化
- 优化地形渲染的内存
- 内存对齐优化不仅性能,而且内存大小
- 优化数据结构,使其充分利用虚拟内存
- 海量数据集中的内存优化
- 针对大型数组的 C# 内存优化
- 内存优化结构cpp