赞
踩
目录
二.扩展(linux下malloc&free是如何实现的?)
四.operator new与operator delete函数
我们直接来看c/c++中的内存区域划分.
①.内核空间: 操作系统内核代码的运行空间.
②.栈: 又叫做堆栈,非静态局部变量/函数形参/返回值/表达式中间结果/某些寄存器信息等等,栈是向下增长的.
③.内存映射段: 是高效的I/O映射方式,用于装载一个共享的动态内存库,用户可以使用系统接口创建共享内存,进行进程间通信.
④.堆: 用于程序运行时动态内存分配,堆是向上增长的.
⑤.数据段: 存储全局数据和静态数据.
⑥.代码段: 可执行的代码/只读常量.
1.堆大小受限于操作系统,而栈空间一般由系统直接分配.
2.频繁的申请空间和释放空间,容易造成内存碎片,甚至内存泄漏,栈区由于是自动管理,不存在此问题.
原因: 我们在堆上动态申请的空间是连续的,而由系统直接分配的栈中的空间是分布式的,不是连续的.
3.栈可以通过函数_alloca进行动态分配,不过注意,所分配空间不能通过free或delete进行释放.
要想了解linux底下malloc和free是如何实现的,我们必须要知道malloc和free的执行原理以及sbrk和brk这两个系统调用函数.
①.malloc&free的执行原理
a. 假设我们使用malloc申请一块空间: int* ptr=(int*)malloc(sizeof(int)); 此时系统会给我们从堆上分配空间,我们申请的是四个字节的空间,但实际占用的并不是四个字节,malloc函数会在我们所申请的四个字节的空间后再增加相应的大小的空间来存储我们所申请的这个空间的大小,以及我们所申请空间相关的信息,另外在这个空间后面还会再增加一块空间用来检测我们所使用的空间是否会越界,因此我们一但使用malloc申请了一块空间我们所得到的空间的大小并不是只有申请的这些,还包括后面的两块空间.(因此当我们申请的空间很小的时候是不建议使用malloc的)
b. 假如我们在自己所写的程序中需要频繁的使用malloc来申请空间,如果每次申请都是从内存中申请的话这样频繁的占用内存将会十分影响我们的程序的运行效率,因此系统为了解决这个问题搞出了一个叫内存池的东西,假如我们在自己编写的程序中第一次使用malloc申请空间不论你申请的空间是大还是小,系统都会先给你分配33页的空间(一页的大小大概率是4kb,当然在不同的系统上可能不一样),当我们所申请的空间大于33页时,后面系统会以一页一页的方式继续进行分配直到满足所申请的空间的大小或者超过系统所能分配的最大的限度为止. 如果我们所申请的空间小于33页时,就会在这以分配好的33页空间中按malloc的执行流程进行创建并返回初始地址,而我们后续继续使用malloc申请空间时依旧会在这33页内存中上次所申请的空间的末尾继续进行分配,无需重新从内存中申请,这样就可以很好的解决我们频繁的使用malloc从内存中申请空间而降低程序效率的问题.
例子: 下面我们写一小段程序验证一下,直接使用malloc申请一个字节的空间,然后循环向后访问空间,33页,每页4kb,每kb1024个字节,因为操作系统可能会在这33页空间中进行某些信息的存储,因此我们不去访问全部的33页,只进行32页的访问即可,也能说明问题,程序完成后,直接编译运行,发现运行正常,程序并没有崩溃或报错.
代码截图:
运行截图:
c.当我们在自己的程序中多次使用malloc申请和释放空间时都会出现这种问题,假如我们分别申请了四次空间其大小分别为: 1.四字节 2.四字节 3.四字节 4.四字节,操作系统底层是以带头结点的双向链表的形式组织这些空间的(具体可看下面malloc/free的模拟实现),因此释放的时候会遵循相应的规律,当我们所要释放的空间到双向链表的末尾位置的所有空间都是空闲状态的时候,才会将这些空间统一释放,否则的话只会将这块空间置为空闲状态,而我们下次再申请空间的时候系统会按我们所申请空间的大小遍历这个双向链表,如果有空闲的空间的大小大于或等于我们要申请的空间的话,系统就会将这块空间的状态重新置为使用状态,并将其首地址返还给用户.(正因为有这条设定,所以我们如果频繁的使用malloc和free申请和释放空间的话一定会产生内存碎片)
例子: 我们先申请三个四字节的int类型的空间并打印其地址,然后释放第二个申请的空间,此时这块空间到双向链表末尾的所有空间并不是都是空闲状态,因此只能将其置为空闲状态,此时我们再申请一块一个字节的char类型的空间,系统遍历双向链表发现刚才第二块int类型所占的空间不仅大于1个字节,并且还是空闲的,因此将其分配给我们来使用,此时编译并运行程序我们发现,a2和a4的地址相同.
代码截图:
运行截图:
②. sbrk
先看该函数的声明:
intptr_t我们将其看做int就行,返回值为指针类型,参数就是我们所申请空间的字节数.
sbrk是一个linux下的系统调用函数,malloc内部就是调用sbrk实现的,该函数是在内部维
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。