浅谈malloc()与free()
malloc()与free()
l 函数原型
malloc函数的函数原型为:void* malloc(unsigned int size),它根据参数指定的尺寸来分配内存块,并且返回一个void型指针,指向新分配的内存块的初始位置。如果内存分配失败(内存不足),则函数返回NULL。
l 关于返回值
malloc的返回值为void*。我们在使用的时候,习惯对返回值进行强制类型转换:
char * p = NULL;
p = (char *)malloc(sizeof(char));
ANSI C以前的C,因为没有void*这种类型,malloc函数的返回值被简单地定义为char*,char*是不能被赋予指向其他类型变量的指针的。所以在使用malloc函数时通常需要对其返回值进行强制类型转换。
在ANSI C中,malloc函数的返回值为void*。void*类型是可以直接赋值给其他任何类型的指针。所以,上面的强制类型转换操作现在已经不需要了。
然而在c++中,任何类型的指针都可以赋给void*,而void*却不可以赋给其他类型的指针,所以在c++中使用malloc函数的时候,强制类型转换是必须的。另一方面,在c++中应该使用new来分配内存。
l malloc在堆上分配内存
malloc函数分配的内存是在堆(heap)上的。操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样代码中的delete或free语句才能正确的释放本内存空间。我们常说的内存泄露,最常见的就是堆泄露(还有资源泄露),它是指程序在运行中出现泄露,如果程序被关闭掉的话,操作系统会帮助释放泄漏的内存。
l malloc的使用
malloc函数使用起来倒是挺简单的,主要的使用范例有两种:一是动态分配结构体,通常用于被称为“链表”的数据结构中;二是分配可变长度的数组。对这两种用法就不多说了,主要是来看使用过程中的注意点:
- 调用malloc函数后,应该对函数返回值进行检查。前面说过,内存分配一旦失败,malloc()会返回NULL。
- char * p = NULL;
- p = (char *)malloc(sizeof(char));
- if(!p)
- exit(1);
- 在程序结束时,应该调用free函数对malloc函数分配的内存进行释放。
实际上,c语言标准没有规定要这么做,而且普通的PC上的操作系统,在进程结束时,肯定会释放曾经分配给当前进程的内存空间,也就是说,在程序结束之前,没有必要调用free()。但是,对于一串连续的程序处理事件,如果先前程序分配的内存没有及时释放掉,那后面的工作就遭殃了。所以”malloc与free配套出现”还是相当合理的。
l malloc()与free( )
从操作系统一次性地取得比较大的内存,当程序调用malloc()时,malloc()便将内存”零售”给应用程序,这是malloc()的大体实现。而当这块一次性取出来的内存不够用的时候,就请求操作系统对空间进行扩容。多次调用malloc()(导致内存不够用了)会调用一次brk(),内存区域向地址较大的一方伸长。malloc()分配内存,会用到brk(用于小内存申请<=128kb,在堆上)或mmap2(用于大内存申请,一般是堆和栈中间)系统调用 。
K&R中记录了malloc()最简单的一种实现方式:通过链表来实现。malloc管理的空间不一定是连续的,空闲存储空间以空闲块链表的方式组织。在这种方式下,每个块之前都加上了一个管理区域,包含一个长度、一个指向下一块的指针以及一个指向自身存储空间的指针。这些快按照储存地址的升序组织。最后一块(最高地址)指向第一块。这里使用K&R中的图加以说明:
当有申请要求时,malloc将扫描空闲块链表,直到找到一块足够大的空闲块为止,如果找不到,则向操作系统申请一个大块并加入到空闲链表中。然而在这种内存管理方式的运行环境中,一旦数组越界检查发生错误,越过了malloc()分配的内存区域写入了数据,将会破坏下一个块的管理区域,容易造成程序崩溃。在《UNIX环境高级编程》中有一段话肯定了以上的说法:
“大多数实现所分配的存储空间比所要求的要稍大一些,额外的空间用来记录管理信息——分配块的长度,指向下一个分配块的指针等等。这就意味着如果写过一个已分配区的尾端,则会改写后一块的管理信息。这种类型的错误是灾难性的,但是因为这种错误不会很快就暴露出来,所以也就很难发现。将指向分配块的指针向后移动也可能会改写本块的管理信息。”
那么,free()在这里做了什么呢?free()将管理区域的标记改为”空块”,顺便也将上下空块合并成一个块,这样也防止了块的碎片化。这么说来,free()函数在调用后,对应的内存是不会立刻返还给操作系统的(还在空闲链表里呆着)。也就是说,调用了free()之后,对应内存的内容不会马上被破坏,直到该块内存被重新分配,里面的内容才会被覆盖重写。尽管如此,调用free()之后,是不能引用对应的内存区域的。所以仓促地使用free()是不对的,特别是当有两个指针指向同一块内存时,指针1把内存释放了,而指针2还指向那块内存,然而指针2已经不能进行解引用了。
这么看来,free()函数实际上并没有做”释放”的实际操作,它只是改变一些状态,告知操作系统某块内存可以去释放。至于如何告诉,还需要后续了解。
浅谈malloc()与free()的更多相关文章
- 从内部入手,浅谈malloc和new的区别
想要理解一样事物,就要先用自己的语言去描述一件事物.在我查阅资料后,发现malloc函数简单说来就是空闲内存空间收集器,并把空闲空间关联起来,用术语来说就是:将空闲内存块合并起来并称为"闲置 ...
- 浅谈malloc()和free()工作原理
编程之路刚刚开始,错误难免,希望大家能够指出. malloc()和free()是我经常需要用到的函数,一般情况下,C程序使用malloc()在堆上分配内存,free()释放内存,两者的参数和返回值就 ...
- 浅谈malloc/free和new/delete 的区别
malloc和new的区别 malloc是库函数,需要包头文件才能成功运行编译:new是操作符(C++中的关键字),需要在C++的环境下使用. malloc既可以在C语言中使用也可以在C++中使用,n ...
- 浅谈C中的malloc和free
转自http://bbs.bccn.net/thread-82212-1-1.html非常感谢作者 浅谈C中的malloc和free 在C语言的学习中,对内存管理这部分的知识掌握尤其重要!之前对C中的 ...
- (转)浅谈C中的malloc和free
原帖及讨论:http://bbs.bccn.net/thread-82212-1-1.html 在C语言的学习中,对内存管理这部分的知识掌握尤其重要!之前对C中的malloc()和free()两个函数 ...
- 浅谈new operator、operator new和placement new 分类: C/C++ 2015-05-05 00:19 41人阅读 评论(0) 收藏
浅谈new operator.operator new和placement new C++中使用new来产生一个存在于heap(堆)上对象时,实际上是调用了operator new函数和placeme ...
- java反射机制浅谈
一.Java的反射机制浅谈 最近研究java研究得很给力,主要以看博文为学习方式.以下是我对java的反射机制所产生的一些感悟,希望各位童鞋看到失误之处不吝指出.受到各位指教之处,如若让小生好好感动, ...
- java的反射机制浅谈(转)
原文链接:java的反射机制浅谈 一.java的反射机制浅谈 1.何谓反射机制 根据网文,java中的反射机制可以如此定义: JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性 ...
- C学习笔记(11)--- 可变参数,浅谈内存管理 【C基础概念系列完结】
1.可变参数(variable arguments): 可变参数允许您定义一个函数,能根据具体的需求接受可变数量的参数. int func(int, ... ) (函数 fun ...
随机推荐
- MVC,MVP 和 MVVM 的图示
作者: 阮一峰 日期: 2015年2月 1日 复杂的软件必须有清晰合理的架构,否则无法开发和维护. MVC(Model-View-Controller)是最常见的软件架构之一,业界有着广泛应用.它本身 ...
- SQL Server系统表sysobjects介绍与使用(转))
这就让sysobjects表格有了用武之地.虽然我不建议你更新这个表格,但是你当然有权对其进行审查. sysobjects 表 在数据库内创建的每个对象(约束.默认值.日志.规则.存储过程等)在表中 ...
- Java核心技术点之注解
本博文是对Java中注解相关知识点的简单总结,若有叙述不清晰或是不准确的地方,希望大家可以指正,谢谢大家:) 一.什么是注解 我们大家都知道Java代码中使用注释是为了向以后阅读这份代码的人解释说明一 ...
- openwrt编译出错处理记录
1.代码从windows复制过来编译报错处理,参考:http://www.360doc.com/content/13/1016/21/3884271_321966616.shtml 2.编译lua-s ...
- linux不同角色server分区方案
服务器角色 分区建议 优点 RAID方案 单机服务器 如8G内存,300G硬盘 /boot 100-200M swap 16G,内存大小8G*2 / 80G /var 20G(也可 ...
- Java7并发编程实战(一) 线程的等待
试想一个情景,有两个线程同时工作,还有主线程,一个线程负责初始化网络,一个线程负责初始化资源,然后需要两个线程都执行完毕后,才能执行主线程 首先创建一个初始化资源的线程 public class Da ...
- PAT1078 Hashing
11-散列2 Hashing (25分) The task of this problem is simple: insert a sequence of distinct positive in ...
- lecture14-RBM的堆叠、修改以及DBN的决策学习和微调
这是Hinton的第14课,主要介绍了RBM和DBN的东西,这一课的课外读物有三篇论文<Self-taught learning- transfer learning from unlabele ...
- JS运动从入门到兴奋1
hello,我是沐晴,一个充满了才华,却靠了照骗走江湖的前端妹子.在这个充满PS的年代,这你们都信,哈哈,废话不多说,今天要分享的是关注JS运动的知识.楼主一直认为,不管学习什么,核心思想才是王道,掌 ...
- UWP 快速的Master/Detail实现
最近在写快报(还没有写完)的过程中,一开始就遇到了这个Master/Detail如何实现的问题. 微软给出Demo并不符合要求,搜索后找到了今日头条开发者写的一篇 :实现Master/Detail布局 ...