为什么局部变量的地址每次都不一样?

我问Google并对StackOverflow进行了一些研究。 我的问题是,当我在C ++程序中输入main()函数并声明第一个变量时,为什么这个变量的地址会因不同的执行而有所不同? 请参阅下面的示例程序:

 #include  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)是OS内存管理中相对较新的创新,它故意使堆栈分配中的内存地址(例如您已观察到的)在运行时尽可能不确定。 这是一个安全function:这可以防止坏的演员利用堆缓冲区溢出,因为如果ASLR实现足够熵,谁知道在溢出缓冲区的末尾会有什么?

您为此和其他内存管理function支付的价格是控制权。 在现代(非嵌入式)平台上投注分配地址就像玩powershell球:可能是一种有趣的分心,但不是一个可行的未来计划。 如果你的代码是在AVR-ISA平台上运行的,或者某些东西,也许这些可能性比二十一点更接近,以至于有人可能被诱惑去玩(可以这么说)。

无论哪种方式,我个人都不是赌博者 – 正如我常说的那样,先生们更喜欢堆叠分配。 但这基本上就是为什么你得到这些结果。

感谢@TC的链接和@SergeyA的建议。