动态内存分配

动态内存分配器管理heap(堆:虚拟内存区域的一部分)。

  • 显式分配器:
    应用分配并且回收空间(C 语言中的 malloc 和 free)
  • 隐式分配器(垃圾收集器):
    检测已分配块不再被程序使用时就释放它。

限制:

  1. 不能操作和修改未分配的内存
  2. 不同的块需要对齐

1.碎片:

  • 内部碎片
    由于实际载荷的大小小于已分配块(例如对齐),所出现的无法利用的空间。
  • 外部碎片
    内存中没有足够的连续空间

2.如何分配:

  1. 空闲块的记录
  2. 分配
  3. 处理每次分配后空闲块的剩余部分
  4. 释放

隐式空闲链表
组成:
这里写图片描述

  • 头部(指针)
    • 块的大小
    • 标记
  • 有效载荷
  • 填充(对齐或者碎片)
  • 脚部:头部的副本(已分配的块不需要脚部)

搜索:

  • 首次适配:从头开始搜索适合的空闲块
  • 下一次适配:从上一次查询的地方开始查询

合并:
通过检查前/后面块的头部是否空闲合并邻近的内存块

  • 立即合并:可能会导致抖动(合并后又马上需要分割)
  • 推迟合并

获取新的堆内存:合并后依然不能获得合适的块,分配器通过sbrk函数向内核请求。

显式空闲链表(双向链表)
增加了头指针和尾指针
管理:

  • LIFO(后进先出):将新释放的块放在链表的开始处
  • 地址顺序

分离存储:
将堆分为多个链表数组,每个数组的块大小各不相同。

  • 简单分离存储:
    已分配的块如果有多余不会分割。
  • 分离适配:
    已分配的块如果有多余,分割剩余部分添加到适合的链表。
  • 伙伴系统:
    块的大小为2^n

3.垃圾收集
这里写图片描述
垃圾收集器将内存视为有向可达图,不可达点为垃圾。
当malloc无法调用合适的空闲块时,调用垃圾收集器通过free函数。
算法:Mark & sweep collection

  1. 标记出根节点所有可达和已分配的后继
  2. 释放未标记的已分配节点

可达节点组成二叉树。首先mark函数标记二叉树的节点,sweep函数将已标记的直接改成未标记,未标记的(不可达节点)直接释放。
这里写图片描述

内存错误:

  1. 解引用错误指针
    例如在应该输入变量地址(&a)时变成了输入变量名(a)。一旦变量名被解析成合法的地址后覆盖原有内容,会难以发现原因。
  2. 读取未初始化的内存
    例如使用未初始化的数组元素。
  3. 覆盖内存
    例如栈缓存区溢出,off-by-one(错位:修改超出数组范围的位置)
  4. 错误使用指针运算
    在本应该移动指针的时候变成了移动指针指向的值。
  5. 内存泄漏(没有释放)
  6. 引用改变后的地址存储的数据。
    例如在函数结束后使用局部变量的地址,或者引用释放后的数据。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值