malloc()与free()

函数原型

malloc函数的函数原型为:void* malloc(unsigned int size),它根据参数指定的尺寸来分配内存块,并且返回一个void型指针,指向新分配的内存块的初始位置。如果内存分配失败(内存不足),则函数返回NULL。

关于返回值

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来分配内存。

malloc在堆上分配内存

malloc函数分配的内存是在堆(heap)上的。操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样代码中的delete或free语句才能正确的释放本内存空间。我们常说的内存泄露,最常见的就是堆泄露(还有资源泄露),它是指程序在运行中出现泄露,如果程序被关闭掉的话,操作系统会帮助释放泄漏的内存。

malloc的使用

malloc函数使用起来倒是挺简单的,主要的使用范例有两种:一是动态分配结构体,通常用于被称为“链表”的数据结构中;二是分配可变长度的数组。对这两种用法就不多说了,主要是来看使用过程中的注意点:

  1. 调用malloc函数后,应该对函数返回值进行检查。前面说过,内存分配一旦失败,malloc()会返回NULL。
    1. char * p = NULL;
    2. p = (char *)malloc(sizeof(char));
    3. if(!p)
    4. exit(1);
  2. 在程序结束时,应该调用free函数对malloc函数分配的内存进行释放。

实际上,c语言标准没有规定要这么做,而且普通的PC上的操作系统,在进程结束时,肯定会释放曾经分配给当前进程的内存空间,也就是说,在程序结束之前,没有必要调用free()。但是,对于一串连续的程序处理事件,如果先前程序分配的内存没有及时释放掉,那后面的工作就遭殃了。所以”malloc与free配套出现”还是相当合理的。

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()的更多相关文章

  1. 从内部入手,浅谈malloc和new的区别

    想要理解一样事物,就要先用自己的语言去描述一件事物.在我查阅资料后,发现malloc函数简单说来就是空闲内存空间收集器,并把空闲空间关联起来,用术语来说就是:将空闲内存块合并起来并称为"闲置 ...

  2. 浅谈malloc()和free()工作原理

    编程之路刚刚开始,错误难免,希望大家能够指出.  malloc()和free()是我经常需要用到的函数,一般情况下,C程序使用malloc()在堆上分配内存,free()释放内存,两者的参数和返回值就 ...

  3. 浅谈malloc/free和new/delete 的区别

    malloc和new的区别 malloc是库函数,需要包头文件才能成功运行编译:new是操作符(C++中的关键字),需要在C++的环境下使用. malloc既可以在C语言中使用也可以在C++中使用,n ...

  4. 浅谈C中的malloc和free

    转自http://bbs.bccn.net/thread-82212-1-1.html非常感谢作者 浅谈C中的malloc和free 在C语言的学习中,对内存管理这部分的知识掌握尤其重要!之前对C中的 ...

  5. (转)浅谈C中的malloc和free

    原帖及讨论:http://bbs.bccn.net/thread-82212-1-1.html 在C语言的学习中,对内存管理这部分的知识掌握尤其重要!之前对C中的malloc()和free()两个函数 ...

  6. 浅谈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 ...

  7. java反射机制浅谈

    一.Java的反射机制浅谈 最近研究java研究得很给力,主要以看博文为学习方式.以下是我对java的反射机制所产生的一些感悟,希望各位童鞋看到失误之处不吝指出.受到各位指教之处,如若让小生好好感动, ...

  8. java的反射机制浅谈(转)

    原文链接:java的反射机制浅谈 一.java的反射机制浅谈 1.何谓反射机制 根据网文,java中的反射机制可以如此定义: JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性 ...

  9. C学习笔记(11)--- 可变参数,浅谈内存管理 【C基础概念系列完结】

    1.可变参数(variable arguments): 可变参数允许您定义一个函数,能根据具体的需求接受可变数量的参数. int func(int, ... )             (函数 fun ...

随机推荐

  1. 未找到数据,异常处理:exception when no_data_found then 异常处理语句;

    未找到数据. 在 select 字段 Into 变量 from 表 where 条件: 这种语句中很有可能会有select 不到数据的问题,导致报错"未找到数据" 要解决这种问题需 ...

  2. C#的匿名方法

    匿名方法是在初始化委托时内联声明的方法. 例如下面这两个例子: 不使用匿名方法的委托: using System; using System.Collections.Generic; using Sy ...

  3. HTML 学习笔记 CSS样式(文本)

    CSS文本属性可以定义文本的外观 通过文本属性 您可以改变文本的颜色 字符间距 文本对齐装饰文本 对文本进行缩进等等. 缩进文本 把web页面上的段落的第一行缩进,这是最常用的文本格式化效果. css ...

  4. (原创)mybaits学习三,springMVC和mybatis融合

    上一节,总计了spring和mybaits的融合,这一节,我们来学习springmvc和mybatis融合 最近在弄一个SSM的项目,然后在网上找资料,将资料总结如下 一,开发环境的配置 MyEcli ...

  5. youtube下载

    http://jingyan.baidu.com/article/39810a23d2deb2b637fda66c.html

  6. tkinter 的两个例子

    第一个例子:after 用于定时操作 import tkinter as tk import time class MyApp(tk.Frame): def __init__(self, msecs= ...

  7. 从Hadoop Summit 2016看大数据行业与Hadoop的发展

    前言: 好吧我承认已经有四年多没有更新博客了.... 在这四年中发生了很多事情,换了工作,换了工作的方向.在工作的第一年的时候接触机器学习,从那之后的一年非常狂热的学习机器学习的相关技术,也写了一些自 ...

  8. HTML5 postMessage 跨域交换数据

    前言 之前简单讲解了利用script标签(jsonp)以及iframe标签(window.name.location.hash)来跨域交换数据,今天我们来学习一下HTML5的api,利用postMes ...

  9. 处理 EF 并发其实就这么简单

    最近项目有点闲,终于可以了解点自己想了解的了,以前听同事讲面试的经历总会被问到“如何处理高并发大数据” 乍一听感觉这东西好像很有学问的样子,于是并发这个词在脑海里留深刻印像,而且在自己心中的技术地位也 ...

  10. [转]Android中Xposed框架篇—利用Xposed框架实现拦截系统方法

    一.前言 关于Xposed框架相信大家应该不陌生了,他是Android中Hook技术的一个著名的框架,还有一个框架是CydiaSubstrate,但是这个框架是收费的,而且个人觉得不怎么好用,而Xpo ...