在 C++ 中玩转内存
Playing with memory in C++
这有点奇怪...我写了一小段代码来为一个整数分配一些内存,保存一个值并打印出保存它的内存地址:
#include <iostream>
using namespace std;
int main (void) {
int * b = new int;
*b = 12345;
cout << " -> *b = " << *b << endl;
cout << " -> b = " << b << endl;
return 0;
}
让我们这样说 returns 以下内容:
-> *b = 123456
-> b = 0x7f9429c04bf0
据我所知,由于我没有主动删除它,所以没有理由不让这个值在内存中冷却 - 所以,为了好玩,我尝试 运行 以下内容:
#include <iostream>
using namespace std;
int main (void) {
int * b = reinterpret_cast <int*> (0x7f9429c04bf0);
cout << " -> *b = " << *b << endl;
cout << " -> b = " << b << endl;
return 0;
}
这会引发段错误 - 有人知道为什么不允许这样做吗?我的意思是......这显然不是一个好主意,我没有计划在实践中使用它,但我很好奇。
干杯!
杰克
每个进程都有自己的虚拟内存space,与其他进程分开。当进程终止时,其内存由操作系统回收。
它抛出段错误的原因是因为 OS 对您的程序试图访问不属于它的内存感到不满。
保护内存背后的整个想法是隔离进程,以便它们不能 弄乱彼此的内存并导致肮脏的事情发生。即使你可以访问随机的内存位置,你也不会在那里真正找到任何有趣的东西。它基本上与访问未初始化指针时得到的东西相同。
即使您同时 运行 这两个程序,我也希望您因此而被踢,而不是得到正确答案。你认为我应该能够通过猜测地址访问另一个程序数据的暗示是可怕的,尽管如果你想要一些历史,曾经有一个名为 "core wars" 的游戏,它涉及这样做以试图让彼此崩溃...
我想真正的答案是它有 "undefined behaviour",你应该庆幸它没有内爆。
大多数现代 C++ 平台都使用底层 OS 提供的 虚拟 内存。虚拟内存并不像您认为的那样是一种微不足道的物理存储形式。虚拟内存只是一种假想的概念存储,它只在进程运行期间存在。每次访问您的进程地址 space 时,它都会模拟 "memory-like" 行为。
您对0x7f9429c04bf0
的访问不是对物理内存地址的访问,而是对进程虚拟地址space的访问,它将被重定向到您无法预测的某个物理位置。
当您的进程结束时,它的虚拟内存将永远消失。无论如何,它是模拟的,某种意义上是假的。当您启动另一个进程时,它会获得自己的虚拟内存,与旧进程没有任何联系。在那个新进程中,访问 0x7f9429c04bf0
将导致您无法预测的其他一些物理位置(或者,如果 0x7f9429c04bf0
甚至无效,则崩溃,如您的情况)。
期望您的值为 "still chilling in memory" 未免太幼稚了。其实你的价值从来没有真正在任何"memory"适合任何一种"chilling".
每个进程都在自己的地址 space 中运行,您传递给 reinterpret_cast 的地址应该可以在 地址 space 当前进程,它不是因为第二个进程有一个 不同的地址 space 布局。此外,即使是第一个程序的每次迭代都会给你不同的地址,这是 ASLR(Address Space Layout Randomization) 的全部要点,即 randomize 每个新实例上进程内存的关键部分。拥有静态地址,就像 ASLR 之前的情况一样,会造成严重破坏,导致易受攻击的程序容易被利用。
阅读有关 ASLR 的更多信息:http://en.wikipedia.org/wiki/Address_space_layout_randomization
虚拟内存:
http://en.wikipedia.org/wiki/Virtual_memory
这有点奇怪...我写了一小段代码来为一个整数分配一些内存,保存一个值并打印出保存它的内存地址:
#include <iostream>
using namespace std;
int main (void) {
int * b = new int;
*b = 12345;
cout << " -> *b = " << *b << endl;
cout << " -> b = " << b << endl;
return 0;
}
让我们这样说 returns 以下内容:
-> *b = 123456
-> b = 0x7f9429c04bf0
据我所知,由于我没有主动删除它,所以没有理由不让这个值在内存中冷却 - 所以,为了好玩,我尝试 运行 以下内容:
#include <iostream>
using namespace std;
int main (void) {
int * b = reinterpret_cast <int*> (0x7f9429c04bf0);
cout << " -> *b = " << *b << endl;
cout << " -> b = " << b << endl;
return 0;
}
这会引发段错误 - 有人知道为什么不允许这样做吗?我的意思是......这显然不是一个好主意,我没有计划在实践中使用它,但我很好奇。 干杯! 杰克
每个进程都有自己的虚拟内存space,与其他进程分开。当进程终止时,其内存由操作系统回收。
它抛出段错误的原因是因为 OS 对您的程序试图访问不属于它的内存感到不满。
保护内存背后的整个想法是隔离进程,以便它们不能 弄乱彼此的内存并导致肮脏的事情发生。即使你可以访问随机的内存位置,你也不会在那里真正找到任何有趣的东西。它基本上与访问未初始化指针时得到的东西相同。
即使您同时 运行 这两个程序,我也希望您因此而被踢,而不是得到正确答案。你认为我应该能够通过猜测地址访问另一个程序数据的暗示是可怕的,尽管如果你想要一些历史,曾经有一个名为 "core wars" 的游戏,它涉及这样做以试图让彼此崩溃...
我想真正的答案是它有 "undefined behaviour",你应该庆幸它没有内爆。
大多数现代 C++ 平台都使用底层 OS 提供的 虚拟 内存。虚拟内存并不像您认为的那样是一种微不足道的物理存储形式。虚拟内存只是一种假想的概念存储,它只在进程运行期间存在。每次访问您的进程地址 space 时,它都会模拟 "memory-like" 行为。
您对0x7f9429c04bf0
的访问不是对物理内存地址的访问,而是对进程虚拟地址space的访问,它将被重定向到您无法预测的某个物理位置。
当您的进程结束时,它的虚拟内存将永远消失。无论如何,它是模拟的,某种意义上是假的。当您启动另一个进程时,它会获得自己的虚拟内存,与旧进程没有任何联系。在那个新进程中,访问 0x7f9429c04bf0
将导致您无法预测的其他一些物理位置(或者,如果 0x7f9429c04bf0
甚至无效,则崩溃,如您的情况)。
期望您的值为 "still chilling in memory" 未免太幼稚了。其实你的价值从来没有真正在任何"memory"适合任何一种"chilling".
每个进程都在自己的地址 space 中运行,您传递给 reinterpret_cast 的地址应该可以在 地址 space 当前进程,它不是因为第二个进程有一个 不同的地址 space 布局。此外,即使是第一个程序的每次迭代都会给你不同的地址,这是 ASLR(Address Space Layout Randomization) 的全部要点,即 randomize 每个新实例上进程内存的关键部分。拥有静态地址,就像 ASLR 之前的情况一样,会造成严重破坏,导致易受攻击的程序容易被利用。
阅读有关 ASLR 的更多信息:http://en.wikipedia.org/wiki/Address_space_layout_randomization 虚拟内存: http://en.wikipedia.org/wiki/Virtual_memory