8/29 深入理解计算机系统 垃圾收集器
9.10 垃圾收集
垃圾收集器是一种动态内存分配器,它自动释放程序不再需要的已分配块。它定期识别垃圾块,调用相应的free,并把这些块放在空闲链表中。
垃圾收集器将内存视为一张有向可达图,图包括根节点和堆节点
每个堆节点对应堆中的一个已分配块。边的方向表示块p中的某个位置指向q的某个位置。根节点是不在堆中,但是包含指向堆的指针。
如果不存在由任意根节点指向p的有向路径,则此节点是不可达的,是垃圾。
JAVA对创建和使用指针有严格的控制,所以可以用可达图精确的表示,但C和C++不行。所以采取的是保守的垃圾收集器。
保守的垃圾收集器只有当malloc找不到空闲块时,调用垃圾收集器,识别垃圾块,调用free。
如果malloc还是失败了就向操作系统分配额外的内存。
Mark & Sweep垃圾收集器
由标记阶段和清除阶段组成:
- 标记阶段标记出所有根节点可达的后继
- 消除阶段释放每个未被标记的已分配块
mark函数一次标记一个根节点的所有未被标记的已分配块
sweep函数在堆中的每个块反复循环,释放它所遇到的所有未标记的已分配块。
C语言中,指针可能不会显示的表明是指针,而是用int。
isptr用平衡二叉树来查找指针是否落在某个块之内。
9.11 C程序常见错误
- 间接引用坏指针
- 读未初始化的内存(堆内存不会初始化为0)
- 允许栈缓冲区溢出(读一个未知的串到有限的数组里)
- 假设指针和它们指向的对象是相同大小的(分配内存时sizeof(int)少了号)
- 造成错位的错误(创建的数组大小是n,初始化了下标为n的元素(第n+1个))
- 误解指针运算(步长不是按位而是按指向的类型)
- 引用不存在的变量(返回已经回收局部变量)
- 引用空闲块中的数据
- 引起内存泄漏