分段错误是由于访问“不属于您”的内存而导致的一种特殊错误,它是一种帮助机制,可以防止您损坏内存和引入难以调试的内存错误。 每当你得到一个segfault,你就知道你正在做一些错误的事情--访问已经被释放的内存变量,写入内存的只读部分,等等。segfault在大多数语言中本质上都是一样的,它让你扰乱内存管理,C和C++中的segfault没有什么主要的区别。
有很多方法可以获得segfault,至少在C(++)这样的低级语言中是这样。 获取segfault的常见方法是取消引用空指针:
int *p = NULL;
*p = 1;
当您尝试写入标记为只读的内存部分时,会发生另一个segfault:
char *str = "Foo"; // Compiler marks the constant string as read-only
*str = 'b'; // Which means this is illegal and results in a segfault
悬空指针指向一个不再存在的东西,像这里:
char *p = NULL;
{
char c;
p = &c;
}
// Now p is dangling
指针P
悬空,因为它指向字符变量C
,该变量在块结束后不复存在。 当您试图取消引用悬空指针(如*p='a'
)时,您可能会得到一个SegFault。
值得注意的是,分段错误并不是由直接访问另一个进程内存引起的(这是我有时听到的),因为这是根本不可能的。 对于虚拟内存,每个进程都有自己的虚拟地址空间,并且无法使用指针的任何值访问另一个虚拟地址空间。 例外的是共享库,它们是相同的物理地址空间,映射到(可能)不同的虚拟地址,内核内存,甚至在每个进程中都以相同的方式映射(我认为是为了避免系统调用上的TLB刷新)。 像shmat;)这样的东西--我把它们算作“间接”访问。但是,我们可以检查它们通常位于离流程代码很远的地方,并且我们通常能够访问它们(这就是它们存在的原因,然而以不恰当的方式访问它们会产生分段错误)。
但是,如果以不正确的方式访问我们自己的(进程)内存(例如试图写入不可写的空间),则可能会发生分段错误。 但最常见的原因是访问虚拟地址空间中根本没有映射到物理地址空间的部分。
所有这些都是关于虚拟内存系统的。
分段错误是由对进程未在其描述符表中列出的页的请求,或者对进程已列出的页的无效请求(例如对只读页的写入请求)引起的。
悬空指针是指可能指向有效页,也可能不指向有效页,但确实指向“意外”内存段的指针。