我已经询问了 Google,并对 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
如您所见,我在不同的执行过程中得到不同的结果。输出的第一行对应于分配内存的地址,这应该发生在堆中——如果它们每次都分配不同的地址,这对我来说有点道理。然而,即使我打印了局部变量的地址——对应于第二行——结果仍然不同。
乍一看,我以为是因为程序正在打印物理内存地址,但这篇文章,Virtual Memory or Physical Memory ,反驳了我最初的想法。鉴于程序的执行是“相同的”,没有线程、没有用户输入等,是否有任何理由仍然存在具有不同地址的内存分配?
测试环境:
- Linux 14.04
- Mac OS X 10.10
最佳答案
在堆上分配时(使用 new
运算符或 malloc()
和 friend ),您的程序必须要求操作系统分配您的堆内存。操作系统内存管理器中发生了很多幕后的事情(其实现细节大多超出我的工资等级:垃圾收集、回收内存的整合等),这是一件好事 不必考虑。
局部变量在栈上分配。传统上,堆栈分配是可重复的,但近年来这种情况发生了变化。 Address space layout randomization (ASR) 是 OS 内存管理中相对较新的创新,它故意使堆栈分配中的内存地址(例如您观察到的那些)在运行时尽可能地不确定。这是一个安全特性:这可以防止不良行为者利用堆缓冲区溢出,因为如果 ASLR 实现足够熵,谁知道溢出缓冲区的末尾会发生什么?
您为此和其他内存管理功能付出的代价是控制权。在现代(非嵌入式)平台上投注分配地址就像玩强力球:可能是一种有趣的分心,但不是 future 可行的计划。如果您的代码在 AVR-ISA 平台或类似平台上运行,则可能与 Blackjack 的赔率更接近,以至于有人可能会被诱骗获胜(可以这么说)。
无论如何,就我个人而言,我不是赌徒——正如我常说的,绅士们更喜欢堆栈分配。但这基本上就是您获得这些结果的原因。
感谢@T.C.链接和@SergeyA 的建议。
关于c++ - 为什么每次局部变量的地址都不一样?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34908728/