动态内存的申请和释放

文章目录

  • 动态内存的申请和释放
    • 1. malloc() 和 free() 的基本概念以及基本用法
      • 1.1 函数原型及说明:
      • 1.2 被释放的指针
      • 1.3 注意事项
    • 2. malloc() 到底从哪里得来了内存空间
      • 2.1 堆介绍
      • 2.2 栈介绍
      • 2.3 栈空间和堆空间的使用方式
    • 3. malloc() 以及 free() 的机制详解

1. malloc() 和 free() 的基本概念以及基本用法

1.1 函数原型及说明:

void *malloc(long NumBytes)

该函数分配了 NumBytes 个字节,并返回了指向这块内存的指针。如果分配失败,则返回一个空指针(NULL)。

关于分配失败的原因,应该有多种,比如说空间不足就是一种。

void free(void *FirstByte)

该函数是将之前用 malloc 分配的空间还给程序或者是操作系统,也就是释放了这块内存,让它重新得到自由,可以被分配给其他函数(进程)。

1.2 被释放的指针

char *p = (char *)malloc(100 * sizeof(char));

当动态内存不再使用,就要将其所指向的空间释放掉,delete 和 free 函数一样,不修改它参数对应指针指向的内容,也不修改指针本身,只是在堆内存管理结构中 将指针指向的内容标记为可被重新分配 。就是告诉系统这个地址的内存我已经不用了,系统可以重新分配给别的程序了,这个地址p的值当然不会变,它只有在生存期结束后才会被释放。

1.3 注意事项

  • 申请了内存空间后,必须检查 是否分配成功

  • 当不需要再使用申请的内存时,记得释放;释放后应该把指向这块内存的指针指向 NULL ,防止程序后面不小心使用了它。

  • 这两个函数应该是配对。如果申请后不释放就是 内存泄露 (内存泄漏(Memory Leak)是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果);如果无故释放那就是什么也没有做。释放只能一次,如果释放两次及两次以上会出现错误(释放空指针例外,释放空指针其实也等于啥也没做,所以释放空指针释放多少次都没有问题)。

  • 虽然malloc()函数的类型是 (void *),任何类型的指针都可以转换成 (void *),但是最好还是在前面进行强制类型转换,因为这样可以躲过一些编译器的检查。

2. malloc() 到底从哪里得来了内存空间

malloc() 到底从哪里得到了内存空间?

答案是从 里面获得空间。也就是说函数返回的指针是指向堆里面的一块内存。操作系统中有 一个记录空闲内存地址的链表 。当操作系统收到程序的申请时,就会遍历该链表,然后就寻找第一个空间大于所申请空间的堆结点,然后就将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。就是这样!

2.1 堆介绍

堆是大家共有的空间,分全局堆局部堆全局堆就是所有没有分配的空间,局部堆就是用户分配的空间。堆在操作系统对进程 初始化的时候分配,运行过程中也可以向系统要额外的堆,但是记得用完了要还给操作系统,要不然就是内存泄漏。

说到堆必然会想到栈。

2.2 栈介绍

栈是线程独有的,保存其运行状态和局部自动变量的。栈在线程开始的时候初始化,每个线程的栈互相独立。栈被用来在函数之间传递参数。操作系统在切换线程的时候会自动的切换栈,就是切换 SS/ESP 寄存器。栈空间不需要在高级语言里面显式的分配和释放。

2.3 栈空间和堆空间的使用方式

栈是由编译器自动分配释放,存放函数的参数值、局部变量的值等。操作方式类似于数据结构中的栈。

堆一般由程序员分配释放,若不释放,程序结束时可能由OS回收。注意这里说是可能,并非一定。所以我想再强调一次,记得要释放!

注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。

所以,举个例子,如果你在函数上面定义了一个指针变量,然后在这个函数里申请了一块内存让指针指向它。实际上,**这个指针的地址是在栈上,但是它所指向的内容却是在堆上面的!**这一点要注意!所以,再想想,在一个函数里申请了空间后,比如说下面这个函数:

void Function(void)
{char *p = (char *)malloc(100 * sizeof(char));
}

就这个例子,千万不要认为函数返回,函数所在的栈被销毁指针也跟着销毁,申请的内存也就一样跟着销毁了!这绝对是错误的!因为申请的内存在堆上,而函数所在的栈被销毁跟堆完全没有啥关系。所以,还是那句话:记得释放!

free() 释放的是指针指向的内存!注意!释放的是内存,不是指针。

3. malloc() 以及 free() 的机制详解

事实上,仔细看一下free()的函数原型,也许也会发现似乎很神奇,free() 函数非常简单,只有一个参数,只要把指向申请空间的指针传递给 free() 中的参数就可以完成释放工作!为什么不需要我们输入申请的空间大小呢?

这里要追踪到 malloc() 的申请问题了。申请的时候实际上占用的内存要比申请的大。因为超出的空间是用来记录对这块内存的管理信息。先看一下在《UNIX环境高级编程》中第七章的一段话:

大多数实现所分配的存储空间比所要求的要稍大一些,额外的空间用来记录管理信息——分配块的长度,指向下一个分配块的指针等等。这就意味着如果写过一个已分配区的尾端,则会改写后一块的管理信息。这种类型的错误是灾难性的,但是因为这种错误不会很快就暴露出来,所以也就很难发现。将指向分配块的指针向后移动也可能会改写本块的管理信息。

以上这段话已经给了我们一些信息了。malloc() 申请的空间实际分配了两个空间。一个就是用来记录管理信息的空间,另外一个就是用户想要的空间。而用来记录管理信息的实际上是一个结构体。在 C 语言中,用结构体来记录同一个对象的不同信息是天经地义的事!下面看看这个结构体的原型:

struct mem_control_block
{int is_available;    //这是一个标记int size;            //这是实际空间的大小
};
void free(void *ptr)
{struct mem_control_block *free;free = ptr - sizeof(struct mem_control_block);free->is_available = 1;return;
}

看一下函数第二句,这句非常重要和关键。其实这句就是把指向可用空间的指针倒回去,让它指向管理信息的那块空间,因为这里是在值上减去了一个结构体的大小! 然后将is_available的值置为1,表明被释放。

动态内存的申请和释放相关推荐

  1. 动态内存的开辟与释放

    //动态内存分配 #include <stdlib.h> #include <stdio.h> #include <string.h> #include <e ...

  2. C++动态内存会被自动释放吗?

    C++动态内存会被自动释放吗? 函数体内的局部变量在函数结束时自动消亡.很多人误以为示例7-6是正确的.理由是p是局部的指针变量,它消亡的时候会让它所指的动态内存一起完蛋.这是错觉! void Fun ...

  3. 结构体的使用和动态内存的分配及释放

    结构体 什么是结构体?结构体是用户根据实际需要自己定义的复合数据类型.结构体的出现是为了表示一些复杂的数据,而普通的数据类型无法满足要求. 结构体的定义: struct Student //struc ...

  4. c语言清理内存程序,C语言中 内存的申请与释放

    内存的申请与释放 对于一段内存的数存,该如何解释,是依赖于数据类型,需要使用 malloc,其使用语法如下: void * malloc(size_t size); 函数 malloc 包含在头文件为 ...

  5. C语言,为什么动态内存分配申请后,还要再释放?

    比如main函数里有一句 malloc(), 后面没有free() 1.那么当main结束后,动态分配的内存不会随之释放么? 2.如果程序结束能自动释放,那么还加上free(),是出于什么考虑? 1. ...

  6. 动态内存的分配与释放

    1.new与delete运算 c++提供了两个中重要的运算符:new和delete.由于他们是运算符不是函数,因此执行效率更高. 运算符 功能 目 结合性 用法 new[] 动态分配 单目 自右向左 ...

  7. C/C++代码调试:快速定位内存的申请和释放的位置

    1.问题 如果大型项目中出现类似于*** glibc detected *** logcacheinit: double free or corruption (fasttop): 0x0000000 ...

  8. Win32 API中内存的申请与释放

    之前在做内存泄漏分析模块功能开发时,发现在windows下的输出结果并不是很准确,很多内存泄漏都显示是在windows的api或crt函数中,比如CoInitializeEx,stderror,IsO ...

  9. 动态链表的创建、节点内存空间申请以及释放

    1.动态链表的初始化: typedef struct _STACK{ void* data;     int size;     struct _STACK* next;     struct _ST ...

最新文章

  1. Android JNI开发流程介绍
  2. session实现机制_如何理解php session运行机制
  3. 【OpenCV 例程200篇】31. 图像金字塔(cv2.pyrDown)
  4. dijkstra算法matlab程序_Dijkstra算法例子
  5. [转] jQuery 选择器
  6. 第十四章:求雨的法术
  7. Linux基本操作和知识
  8. sqark sql练习之统计UV
  9. 权御天下计算机音乐数字乐谱,权御天下(单音 适合电吉他)
  10. Rust: flat_map、filter_map、for_each
  11. 微信公众号选择什么服务器好,微信开发选择订阅号还是服务号好?
  12. uniapp 权限判断 判断位置,摄像头,相册,通讯录是否开启,如果没有开启弹窗提示并且进入设置打开权限
  13. 转:红帽旗下Linux的版本说明RedHat、CentOS、Fedora、OEL等
  14. 【C语言】C语言中基础操作符详细讲解
  15. 利用XML制作UGUI登陆界面
  16. linux3.0字符设备驱动,v4l2驱动3-linux3.0.8中v4l2_format详解
  17. lucene配置动态域_学位论文查重中如何使用Lucene全文检索
  18. python调用打印机参考例子_Python调用打印机参考例子
  19. Babuk勒*索软件(病*毒)解密
  20. 香港旅游必去景点TOP10

热门文章

  1. 百度云推送-----10101错误
  2. 项目笔记一-----------------iphone官网仿制
  3. 便宜的数据库_您会为了便宜的娱乐而放弃多少数据
  4. crash: mod命令
  5. 深圳软件测试培训:瓶颈分析方法
  6. NYOJ 小珂的烦恼
  7. ruby的DIR.pwd
  8. 二十四节气之小暑养生篇
  9. 上海盲人计算机培训,一位盲童:2018上海高考前十名|特教人物
  10. Flex Builder 3的破解