操作系统(10)虚拟内存-常见内存有关错误
在虚拟内存系统中,常见的内存相关错误主要源于地址访问非法、内存管理操作不当等原因,以下是典型错误及解析:
10.1 段错误
这是最常见的内存错误,因进程访问了无权限的虚拟地址导致。
1. 访问空指针(NULL 指针解引用)
int *p = NULL;
*p = 10; // 错误:访问地址0x0,无权限
原因:NULL 指针通常映射到虚拟地址空间的起始区域,操作系统未给该区域分配权限,访问时触发段错误。
2. 访问已释放内存(野指针)
int *p = malloc(4);
free(p);
*p = 20; // 错误:p成为野指针,指向的内存已被回收
原因:free(p) 后,p 指向的内存已归还分配器(可能被重新分配或标记为空闲),再次访问属于非法操作。
3. 越界访问数组 / 缓冲区
char buf[10];
strcpy(buf, "这是一个超过10字节的字符串"); // 错误:数组越界
原因:写入超出数组分配的虚拟地址范围,可能覆盖其他变量或程序元数据,触发段错误。
4. 访问内核空间地址
用户进程的虚拟地址空间中,内核区域(如高地址部分)无访问权限,若强行访问会触发段错误:
void *kernel_addr = (void*)0xFFFF800000000000;
*((int*)kernel_addr) = 0; // 错误:用户态访问内核地址
10.2 内存分配与释放错误
这类错误会导致内存泄漏、双重释放、内存损坏等问题。
1. 内存泄漏(Memory Leak)
动态分配的内存未释放,导致进程占用的内存持续增长,最终可能耗尽系统内存:
void func() {while (1) {malloc(1024); // 错误:未调用free,内存持续泄漏}
}
2. 双重释放(Double Free)
对同一块内存调用多次 free,会破坏分配器的空闲块链表,导致程序崩溃或内存损坏:
int *p = malloc(4);
free(p);
free(p); // 错误:双重释放
3. 释放非动态分配内存
对栈内存或全局内存调用 free,会破坏分配器的元数据:
int a = 10;
free(&a); // 错误:栈内存不能用free释放
10.3 虚拟内存缺页异常相关错误
缺页异常是虚拟内存的正常机制,但以下情况会导致异常终止。
1. 非法缺页访问
若缺页时发现虚拟地址既不在合法区域,也无有效权限,会触发段错误。例如:
访问未映射的虚拟地址(如随机地址
0x12345678)。对只读区域执行写操作(如修改代码段)。
2. 内存交换失败(SIGBUS)
若缺页时需要将脏页(修改过的页)交换到磁盘,但磁盘 I/O 失败(如磁盘满、文件损坏),会触发 SIGBUS 信号终止进程。
10.4 内存对齐错误
部分硬件或系统要求内存访问必须地址对齐(如 int 型需 4 字节对齐),否则触发错误。
char buf[3];
int *p = (int*)&buf[1]; // 错误:p的地址是奇数,未4字节对齐
*p = 10; // 可能触发总线错误(SIGBUS)
10.5 多线程内存竞争错误
多线程同时操作同一块动态内存时,若缺乏同步,会导致内存损坏。
int *p = malloc(4);
void *thread1() { *p = 1; }
void *thread2() { *p = 2; }
// 错误:两个线程同时写p,可能导致内存内容混乱或分配器元数据损坏
