为何现代操作系统大多弃用分段机制,C语言中仍会出现Segmentation Fault?
为什么现代操作系统不再使用硬件分段,还会出现Segmentation Fault?
问题1:Segmentation Fault的命名属于历史遗留
- 这个错误名称确实起源于早期依赖分段做内存管理的操作系统,但现在已经成为非法内存访问类错误的通用命名,和当前底层是否使用硬件分段没有绑定关系。
- 现在主流操作系统的内存保护完全基于分页机制实现:当进程尝试访问未被映射到当前进程地址空间的虚拟地址、或者访问的地址不符合页表标注的权限(比如尝试写只读的代码段、访问没有用户态权限的内核地址、访问已经释放的内存页),MMU会触发页错误,操作系统判断该访问为非法操作后,会向进程发送
SIGSEGV信号,对应的用户态报错提示就沿用了早年的“Segmentation Fault”(段错误)称呼。
举个最常见的触发示例:
int main() { int *null_ptr = NULL; *null_ptr = 1; // 尝试向未映射的空地址写入数据 return 0; }
这段代码运行后得到的段错误,本质就是分页机制识别到空地址没有被映射到进程的合法内存页,直接拦截访问后抛出的错误,和硬件分段没有任何关系。
问题2:现代操作系统是否还保留分段抽象
要分硬件特性使用和逻辑抽象两层来看:
- 硬件层面:以x86架构为例,硬件原生还保留了完整的分段机制,但Linux、Windows、macOS等主流系统都默认将所有段的基址设为0、段限长设为整个虚拟地址空间的最大值,相当于几乎绕开了分段的地址转换能力,仅利用分段的少量附加特性实现特定功能:比如通过CS段的特权级位区分内核态和用户态,通过FS/GS段存储线程本地存储(TLS)的基地址,没有用分段实现内存隔离、地址空间管理的核心功能。
- 逻辑抽象层面:绝大多数操作系统都会把进程的虚拟地址空间按用途划分为不同的逻辑段,比如代码段(text)、初始化数据段(data)、未初始化数据段(bss)、堆、栈、共享库映射区等。这里的“段”完全是操作系统层面的逻辑划分,和硬件的分段机制没有关联,划分的目的是更方便地基于分页机制管理不同区域的内存权限,比如代码段设为可读可执行不可写,栈设为可读可写不可执行,都是通过修改页表的权限位实现的。
内容的提问来源于stack exchange,提问作者Clinton Kavai
相关产品推荐
相关产品推荐

