内存分配

内存分配方式

  • 从静态存储区域分配
    内存在程序编译时就已分配好,这块内存在程序的整个运行期间都存在,
    如:全局变量,static变量

  • 在栈上创建
    在执行函数时,函数内局部变量的存储单元都可在栈上创建,函数执行结束时这些存储单元自动释放
    栈内存分配运算内置于处理器的指令集中,效率很高,但分配的内存容量有限

  • 从堆上分配,亦称动态内存分配
    程序在运行时,用malloc或new申请任意多少的内存,程序员自己负责在何时使用free或delete释放内存
    动态内存的生存期由程序员决定,使用灵活

C语言中内存申请相关的函数

alloca、calloc、malloc、free、realloc、sbrk

  • alloca是向栈申请内存,因此无需释放;malloc分配的内存位于堆中,且没初始化内存的内容。因此,在malloc之后,调用memset来初始化这部分的内存空间
  • calloc将初始化这部分的内对空间设置为0
  • realloc对malloc申请的内存进行大小的调整,申请的内存最终通过free来释放
  • sbrk增加数据段的大小
  • malloc、calloc和free都是C函数库实现的,与OS无关
    C函数库内部通过一定的结构来保存当前有多少可用内存,若程序申请的malloc的大小超过库里所留的空间,则将先调用sbrk系统调用来增加可用空间,再进行分配空间

free时,释放的内存并不立即返回给OS,而是保留在内部结构中。

sbrk类似批发,一次性向OS申请大的内存,malloc等类似零售,满足程序运行时需求,这套机制类似缓冲。

基于这套机制开发的原因:
● 系统调用不能支持任意大小的内存分配,有的系统调用只支持固定大小即其倍数的内存申请,这样会造成需使用小内存而申请大内存空间的浪费
● 系统调用申请内存代价大,涉及用户态到内核态的转换

malloc和calloc分配动态内存空间

区别

  • malloc( )函数有一个参数,即所分配内存空间的大小
    void *malloc(size_t size);
    calloc( )函数有两个参数,分别为元素数目和元素大小,参数乘积为要分配的内存空间大小
    void *calloc(size_t numElements, size_t sizeOfElement);
    若调用成功,函数malloc( )和calloc( )都将返回所分配的内存空间的首地址

  • malloc( )不能初始化所分配的内存空间,calloc( )可以
    若malloc函数分配的内存空间之前没使用过,则每一位可能都是0;但这部分空间曾被分配、释放或重新分配,则可能存留各种各样的数据。换句话说,即使用malloc函数的程序开始时(内存空间没重新分配)能正常运行,但经过一段时间后(内存空间)可能出现问题
    calloc函数会将所分配的内存空间中的每一位都初始化为0

  • malloc函数只返回一个对象,而calloc函数会返回一个由某种对象组成的数组。如为数组分配内存空间时,可选用calloc函数

总结:

  1. 在calloc函数和malloc函数之间选择时,只需考虑是否初始化所分配的内存空间,而不要考虑函数是否能返回一个数组。因为,尽管malloc并不能返回一个数组,但它所分配的内存空间仍能供一个数组使用
  2. 当程序运行中有malloc时,但没有free,会造成内存泄露。由于一部分内存未被使用而又没被free,因此系统认为这部分内存仍在使用,造成不断的向系统申请内存,使系统可用内存不断减少。但是,内存泄露仅仅指程序在运行时,程序退出时,OS将回收所有资源