Fork Me
内存管理 & 段错误
17 Oct 2014 - by @ssdr

内存管理的三个层面

  • 用户管理层
  • 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,有时什么也没发生