动态内存分配
来源:互联网 发布:手机验证码软件 编辑:程序博客网 时间:2024/05/18 00:20
动态内存分配器管理heap(堆:虚拟内存区域的一部分)。
- 显式分配器:
应用分配并且回收空间(C 语言中的 malloc 和 free) - 隐式分配器(垃圾收集器):
检测已分配块不再被程序使用时就释放它。
限制:
- 不能操作和修改未分配的内存
- 不同的块需要对齐
1.碎片:
- 内部碎片
由于实际载荷的大小小于已分配块(例如对齐),所出现的无法利用的空间。 - 外部碎片
内存中没有足够的连续空间
2.如何分配:
- 空闲块的记录
- 分配
- 处理每次分配后空闲块的剩余部分
- 释放
隐式空闲链表
组成:
- 头部(指针)
- 块的大小
- 标记
- 有效载荷
- 填充(对齐或者碎片)
- 脚部:头部的副本(已分配的块不需要脚部)
搜索:
- 首次适配:从头开始搜索适合的空闲块
- 下一次适配:从上一次查询的地方开始查询
合并:
通过检查前/后面块的头部是否空闲合并邻近的内存块
- 立即合并:可能会导致抖动(合并后又马上需要分割)
- 推迟合并
获取新的堆内存:合并后依然不能获得合适的块,分配器通过sbrk函数向内核请求。
显式空闲链表(双向链表)
增加了头指针和尾指针
管理:
- LIFO(后进先出):将新释放的块放在链表的开始处
- 地址顺序
分离存储:
将堆分为多个链表数组,每个数组的块大小各不相同。
- 简单分离存储:
已分配的块如果有多余不会分割。 - 分离适配:
已分配的块如果有多余,分割剩余部分添加到适合的链表。 - 伙伴系统:
块的大小为2^n
3.垃圾收集
垃圾收集器将内存视为有向可达图,不可达点为垃圾。
当malloc无法调用合适的空闲块时,调用垃圾收集器通过free函数。
算法:Mark & sweep collection
- 标记出根节点所有可达和已分配的后继
- 释放未标记的已分配节点
可达节点组成二叉树。首先mark函数标记二叉树的节点,sweep函数将已标记的直接改成未标记,未标记的(不可达节点)直接释放。
内存错误:
- 解引用错误指针
例如在应该输入变量地址(&a)时变成了输入变量名(a)。一旦变量名被解析成合法的地址后覆盖原有内容,会难以发现原因。 - 读取未初始化的内存
例如使用未初始化的数组元素。 - 覆盖内存
例如栈缓存区溢出,off-by-one(错位:修改超出数组范围的位置) - 错误使用指针运算
在本应该移动指针的时候变成了移动指针指向的值。 - 内存泄漏(没有释放)
- 引用改变后的地址存储的数据。
例如在函数结束后使用局部变量的地址,或者引用释放后的数据。
阅读全文
0 0
- 动态内存分配
- 关于动态内存分配
- 关于动态内存分配
- 动态内存分配
- 动态内存分配
- 动态内存分配
- 动态内存分配
- 动态内存分配
- C++ 动态内存分配
- VC动态内存分配
- 动态数组分配内存
- C++动态内存分配
- 动态内存分配
- 动态内存分配
- 动态内存分配
- 动态内存分配
- 动态内存分配+链表
- 动态内存分配函数
- NIO简单理解(一,NIO服务端简单实现逻辑)
- 如何优化深度神经网络
- 关于数据库‘状态’字段设计的思考与实践
- 做了一个进度条
- hdu 6143
- 动态内存分配
- cent os 7 下安装tensorflow
- unity 各个平台下运行使用
- redis必杀高级:客户端连接
- MP4文件格式解析
- 固态硬盘SSD与机械硬盘HDD
- Java Socket实现基于TCP和UDP多线程通信
- Ubuntu镜像下载
- Git-在Centos7.2下安装Git服务器