我正在研究给定进程的内存布局。我注意到每个进程的起始内存位置不是0.在这个website上,TEXT从0x08048000开始。一个原因可以是使用NULL指针区分地址。我只是想知道是否还有其他好的理由?感谢。
答案 0 :(得分:3)
空指针实际上不必为0.在C标准中保证当在指针的上下文中给出0值时它被视为{{1编译器。
但是你在源代码中使用的0只是 syntactic sugar ,它与实际的物理地址无关,空指针值是"指向"到。
有关详细信息,请参阅:
您的操作系统上的应用程序有其独特的地址空间,它被视为连续的内存块(内存不是物理上连续的,它只是"印象"操作系统给每个程序。)
在大多数情况下,每个进程的虚拟内存空间都以类似且可预测的方式布局(这是Linux进程中的内存布局,32位模式):
(图片来自Anatomy of a Program in Memory)
查看文本段(x86上的默认.text基础是0x08048000,由静态绑定的默认链接描述文件选择)。
为什么神奇的0x08048000?可能是因为Linux从System V i386 ABI中借用了该地址。
......为什么System V使用0x08048000?
选择该值以容纳.text部分下面的堆栈, 向下发展。 0x48000字节可以由同一页面映射 .text部分已经需要的表(从而保存了一个页表 在大多数情况下),而剩余的0x08000000将允许更多的空间 对于渴望堆栈的应用程序。
有什么低于0x08048000吗?什么都没有(它只有128M),但是you can pretty much map anything you desire there, using the mmap() system call。
另见:
答案 1 :(得分:2)
我认为这总结了一下:
每个进程都有自己的一组页表,但有一个问题。启用虚拟地址后,它们将应用于计算机中运行的所有软件,包括内核本身。因此,必须为内核保留一部分虚拟地址空间。
因此,虽然该过程获得了自己的地址空间。如果不向内核分配块,它将无法解决内核代码和数据。
这始终是它出现的第一个内存块,因此包含地址0.用户模式空间超出此范围,因此堆栈和堆都驻留在这里。
区别于NULL
指针
即使用户模式空间在地址0
处开始,也不会有任何数据分配给地址0
,因为它将位于堆栈或堆中,而这些数据本身不会从用户区的开头。因此,NULL
(值0
)仍然可以使用,并且不是此布局的原因。
然而,与NULL
和第一个块是内核内存相关的一个好处是任何读取/写入NULL的尝试都会引发分段错误。
答案 2 :(得分:0)
loader 将 segments 中的二进制文件加载到内存中:text(常量),数据,代码。没有必要从0开始,因为C有来自bug的访问的问题,就像a[i]
中甚至是危险的一样。这允许(在某些处理器上)拦截分段错误。
这将是C运行时从0引入线性地址空间。这可能是可以想象的,其中C是操作系统的实现语言。但没有任何目的;让堆从0开始。内存模型是一个段。某些处理器可能会保护代码段不被修改。
在段中,分配发生在C运行时管理的内存块中。
我可以补充一点,操作系统本身经常使用物理0及以上。