1. 内存泄漏
内存泄漏是程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果
linux检测内存泄漏的工具
mtrace
valgrind
2. 什么是内存碎片,怎么避免内存碎片
new申请大量不连续的空间后,剩余可用内存分布零散,无法被有效使用。这些零散的可用内存叫内存碎片。
内存碎片分为内部碎片和外部碎片
用户作业的地址空间一般分成若干大小相同的页,存储空间也分成页大小相等的物理块,用户申请的内存大小不一定和页块大小相等,因此有一部分页空间被浪费了,称为内碎片。
系统按一定的分配算法从内存中分配一块空间区,如果容量比用户申请的大,则一分为二,由此,可能剩下一些零散的内存块无法被使用,称之为外碎片
linux如何避免内存碎片
1. 伙伴算法,用于管理物理内存,避免内存碎片
2. 高速缓存slab层,用于管理内存分配内存,避免碎片
解决外碎片一般有两种方法:一是使用地址转换奇数,把非连续的物理地址转成连续的线性地址。二是使用特殊的分配技术记录空闲内存情况
3. C++五大存储区
1. 栈,编译器自动分配释放,windows默认2M,linux默认8M栈,
ulimit -a 查看当前设置,ulimit -s 16384设置为16兆,可以修改系统配置文件
2. 堆,由程序员使用malloc、free等分配释放,是操作系统的术语,由操作系统维护,不连续的空间,理论上是硬盘的大小
3. 自由存储区,是C++使用new、delete分配和释放对象的抽象概念,基本上所有的C++编译器都是用堆实现自由存储
4. 静态/全局数据区,分为初始化区和未初始化区两部分,大小2G,未初始化时系统自动置0
5. 常量区,字符串常量等
6. 代码区
static全局变量和static局部变量,都存放在静态/全局区
const全局变量存放在静态/全局数据区,编译器最初保存在符号表中,第一次使用时分配内存,程序结束时释放,const局部变量放在栈区,代码块结束时释放。
全局变量存放在静态/全局数据区,编译时分配内存,程序结束时释放。
局部变量存储在栈中,代码块结束时释放
4. linux操作系统对内存的管理
linux内核通过把整个物理内存划分成一个个的page页进行管理,管理器就是伙伴系统,它的最小分配单元就是page,对于小于page的内存分配, 通过slab实现内存分配,slab把page按2的m次幂进行划分,由slab管理器返回满足条件的最小空闲内存块。
1. 伙伴系统把所有空闲页框分成11个块链表,每个链表包含大小为1,2,4,8。。。1024个连续的页框(每页大小为4K)。
如果请求一个256个页框的内存块,算法如下:
在256页框的链表中,检查是否有空闲块,有则满足申请,没有则查找下一个更大的块
在512页框的链表中,检查是否有空闲块,有则把512个页框分成两份,第一份满足申请,第二份连接到256页框的链表中, 如果没有空闲块,则继续找下一个更大的
释放过程和申请相反,内核试图将大小为B两个空闲块,合并为一个大小为2B的空闲块:两个块必须有相同的大小。他们的物理地址是连续的
2. slab是linux系统的一种内存分配机制,针对一些经常分配并释放的对象,如进程描述符等。这些对象向大小一般都很小。
slab分配算法使用cache存储内核对象。linux的slab有三种状态:
满的:slab中所有的对象都被标记位使用
空的:slab中所有的对象都被标记位空闲
部分:slab中的对象有的空间,有的使用
slab分配器先从部分空闲的slab进行分配,如果没有空闲的,则从空的slab进行分配,如果没有,则从物理连续页上分配新的slab,并把它赋给一个cache,然后再从新的slab进行分配。
5. 内存池的作用及实现方法
内存池的作用:
1. 直接使用系统的malloc/free和new/delete进行内存的分配和释放,系统会使用伙伴系统和slab机制,使用某种算法在内存矿中查找空闲块,并在释放时进行合并,产生开销
2. 频繁使用时会产生大量内存碎片,降低系统运行效率
3. 容易造成内存泄漏
C++的空间配置器设计
第一级配置器使用malloc free realloc 执行实际的内存分配,释放和重新配置操作
第二级配置器维护一个内存池,做法是:
如果区块够大,超过128bytes时,转交第一级配置器处理
如果下雨128bytes时,则以内存池管理。使用一个union ojb数组 free_list用来存储内存的地址,数组的每一个元素都指向一个ojb内存链表,数组大小表示8B,16B,24B ... 128B的内存,当请求内存为n时,上升为8的倍数,并从相应的链表中分配对应的内存块。
如果没有内存块可用,则重新填充默认20个新节点
释放时根据内存的大小,找到对应大小的链表,并插入到链表