为什么局部变量的地址每次都不同
Why the addresses of local variables can be different every time?
我问过谷歌,并对StackOverflow做了一些研究。我的问题是,当我在C++程序中输入main()
函数并声明第一个变量时,为什么这个变量的地址会随着不同的执行而变化?请参阅下面的示例程序:
#include <iostream>
int main() {
int *a = new int;
int *b = new int;
std::cout << "address: " << a << " " << b << std::endl;
std::cout << "address of locals: " << &a << " " << &b << std::endl;
return 0;
}
执行 1 的结果:
address: 0xa32010 0xa32030
address of locals: 0x7fff10de2cf0 0x7fff10de2cf8
执行结果 2:
address: 0x1668010 0x1668030
address of locals: 0x7ffc252ccd90 0x7ffc252ccd98
执行结果 3:
address: 0x10e0010 0x10e0030
address of locals: 0x7ffd3d2cf7f0 0x7ffd3d2cf7f8
如您所见,我在不同的执行中得到不同的结果。输出的第一行对应于分配内存的地址,这应该发生在堆中——如果每次都为它们分配不同的地址,这对我来说有点意义。但是,即使我打印局部变量的地址(对应于第二行),结果仍然不同。
乍一看,我以为这是因为程序正在打印物理内存地址,但是这篇文章,虚拟内存或物理内存,反驳了我最初的想法。鉴于程序的执行是"相同的",没有线程,没有用户输入等,是否有任何理由仍然存在具有不同地址的内存分配?
测试环境:
- Linux 14.04
- Mac OS X 10.10
在堆上分配时(使用 new
运算符或malloc()
和朋友),您的程序必须要求操作系统分配您的堆内存。操作系统内存管理器中发生了许多幕后的事情(其实现细节大多高于我的工资等级:垃圾收集,回收内存的整合等),这是一件好事不必考虑它。
局部变量在堆栈上分配。 传统上,堆栈分配是可重复的,但近年来这种情况发生了变化。地址空间布局随机化 (ASR) 是操作系统内存管理中相对较新的创新,它有意使堆栈分配(例如您观察到的那些)中的内存地址在运行时尽可能不确定。这是一项安全功能:这可以防止不良行为者利用堆缓冲区溢出,因为如果 ASLR 实现足够熵,谁知道溢出缓冲区的末尾会发生什么?
您为此和其他内存管理功能付出的代价是控制。 在现代(非嵌入式)平台上押注分配地址就像玩强力球:可能是一种有趣的分心,但不是未来的可行计划。如果您的代码在 AVR-ISA 平台或类似平台上运行,也许赔率更接近二十一点,以至于有人可能会被诱惑玩游戏以获胜(可以这么说)。
无论哪种方式,我个人都不是一个赌博的人——正如我常说的,绅士们更喜欢筹码分配。但这基本上就是你得到这些结果的原因。
感谢@T.C.的链接和@SergeyA的建议。
- libmysql:警告:返回局部变量"行"的地址(C++/C)
- 从函数返回变量地址时如何修复"与局部变量关联的堆栈内存地址"?
- 变量循环范围会导致返回局部变量的地址引用
- 局部变量保存相同的内存地址
- 使用函数模板中静态局部变量的地址作为类型标识符是否安全
- 警告:返回局部变量'buffer'地址
- 返回的与局部变量关联的堆栈内存的地址 (C++)
- 局部变量的地址
- 警告:返回局部变量"角度"的地址 [-Wreturn-local-addr]
- 是否释放了局部变量的地址
- 局部变量和其他变量类型的地址存储在哪里
- 局部变量的内存地址根据 lambda 参数的预感而变化
- 我想返回局部变量的地址
- 为什么局部变量的地址每次都不同
- 将局部变量的地址作为C++11中的常量表达式
- 为什么编译器在编译时不知道局部变量的地址?
- 更改局部变量的地址
- 局部变量的返回地址和程序仍然有效
- 为什么局部变量的地址对于不同的执行是相同的
- 将地址返回给局部变量与返回指向局部变量的指针