内存管理的三个层面
- 用户管理层
- C运行时库层
- 操作系统层
内存管理方法
- C风格内存管理
- 池式内存管理
- 引用计数
- 垃圾收集
内存管理设计目标
- 最大化兼容性
- 最大化可移植性
- 浪费最小的空间
- 最快的速度
- 最大化可调用性
- 最大化局部性
- 最大化调试功能
- 最大化适应性
32位模式下进程默认内存布局:4GB
---------------------------------------------
|--0 |
|--128M |
|---------------------------------------------|
| text segment (ELF): 程序二进制文件 |
| data segment:用户初始化的静态变量 |
| bss segment:未初始化静态变量,填充0 |
|---------------------------------------------|
|--random brk offset |
|-------------------| |
| heap: grow up |
| ... |
|---------------------------------------------|
| ... |
| memory mapping segment: 文件映射grow down|
|-------------------| |
|--random mmap offset |
|---------------------------------------------|
| ... |
| stack: grow down |
|-------------------| |
|--random stack offset |
|---------------------------------------------|
|--3G |
| kernel space |
---------------------------------------------
内存相关问题
- 缓冲区溢出
- 空悬指针/野指针
- 重复释放
- 内存泄漏
- 不配对的new[]/delete
- 内存碎片
系统调用通常提供一种最小功能,而库函数通常提供比较复杂的功能。
内核数据结构mm_struct。
段错误
segmentation fault (SIGSEGV)
是一个用户态的概念,是操作系统在用户态程序错误访问内存时所做出的处理。
SIGSEGV在很多时候是由于指针越界
引起的,但不是所有的指针越界都会引起SIGSEGV,如果不解引用
它,是不会发生SIGSEGV的。
而即使解引用了一个越界指针,也不一定会引起SIGSEGV。
几种引起段错误的原因。
错误的访问类型引起
char *s = "hello world";
s[1] = 'E';// SIGSEGV, 常量字符串在最后链接阶段被合并到text segment与代码段合并到一起,处于只读区域
访问不属于进程地址空间的内存
int *p = (int *)0xc0000fff;
*p = 10;// SIGSEGV
访问了不存在的内存
int *a = NULL;
*a = 1;// SIGSEGV
栈溢出/函数返回绝不变量引用
栈溢出/函数返回绝不变量引用,有时SIGSEGV,有时什么也没发生。