malloc函数是C/C++中常用内存分配库函数,本篇文章将以Linux平台上的malloc为剖析对象,深入了解分配一块内存的旅程。

malloc入门

     使用malloc,需要包含头文件 stdlib.h ,函数原型如下:

      extern void *malloc(unsigned int num_bytes);

     功能: 分配长度为 num_bytes的内存块,如果分配成功,则返回指向被分配内存的指针,否则返回空指针NULL,否则发生的情况,一般为系统堆上可用的内存上无法找到一块长度大于num_bytes的连续内存空间。

     特别情况:如果num_bytes为0,malloc成功分配0字节的空间,返回一个有效指针,但无法使用此指针。

     当内存不再使用时,应使用free函数将内存块释放。

     返回值类型为void*,表示未确定类型的指针,它可以强制转换为任何其他类型的指针。

     

     extern  free(void *FirstByte);

     功能: 将之前malloc分配的空间还给操作系统,释放传入指针指向的那块内存区域,指针本身的数值没变,释放前,指向的内容是可理解的,释放后,指向的内容是垃圾内容。

     注意: 释放空指针,不会出错。释放同一个有效指针两次,会出错。释放后,最好把指向这块内存的指针指向NULL,防止后面的程序误用。

malloc深入了解

     glibc库实现了malloc,它实现linux系统的堆管理。在Linux中,大部分的系统调用都是通过C库函数来体现了,因此glibc就显得尤为重要。glibc的实现策略和Windows的类似,都是维护一个全局链表,每个链表元素由不定长的内存块链表。

    与Windows不同的是,在glibc中,维护了多个不定长的内存块链表,每一个链表负责一个大小范围,这种做法有效减少了分配大内存时的遍历开销,类似于哈希的方式,将很大的范围的数据散列到有限的几个小的范围内而不是所有数据都放在一起,虽然最终还是要在小的范围内查找,但是最起码省去了很多的开销,如果只有一个不定长链表那么就要全部遍历,如果分成3个,就省去了2/3的开销,总之这个策略十分类似于散列。glibc另外的策略就是不止维护一类空闲链表,而是另外再维护一个缓冲链表和一个高速缓冲链表,在分配的时候首先在高速缓存中查找,失败之后再在空闲链表查找,如果找到的内存块比较大,那么将切割之后的剩余内存块插入到缓存链表,如果空闲链表查找失败那么就往缓存链表中查找. 如果还是没有合适的空闲块,就向内存申请比请求数更大的内存块,然后把剩下的内存放入链表中。这种方式是glibc自己实现的策略。

     malloc函数,它内部有一个将多个可用内存块连接为一个空闲链表。在调用时,它沿链表寻找一个大到足以满足用户请求所需要的内存块。然后,将该内存块一分为二(一块的大小与用户请求的大小相等,另一块的大小就是剩下的字节)。接下来,将分配给用户的那块内存传给用户,并将剩下的那块(如果有的话)返回到链接表上。

     调用free函数时,它将用户释放的内存块回收到空闲链表。到最后,空闲链会被切成很多的小内存片段,如果这时用户申请一个大的内存片段,那么空闲链上可能没有可以满足用户要求的片段了。于是,malloc函数请求延时,并开始在空闲链上翻箱倒柜地检查各内存片段,对它们进行整理,将相邻的小空闲块合并成较大的内存块。

《UNIX环境高级编程》第七章:

  从glibc中malloc的详细解释一文中知道:

 

  在glibc的malloc实现中,分配虚存有两种系统调用可用,brk和mmap2,根据默认门限值来决定具体调用哪个进行分配。

 

malloc返回的每块内存的起始处首先要有这个结构:

内存控制块结构定义
struct mem_control_block {
     int is_available;
     int size;
};

free函数比较简单,给出来。

4. 解除分配函数 free
void free(void *firstbyte) {
struct mem_control_block *mcb;
/* Backup from the given pointer to find the
* mem_control_block
*/
mcb = firstbyte - sizeof(struct mem_control_block);
/* Mark the block as being available */
mcb->is_available = 1;
/* That''s It! We''re done. */
return;
}

    free函数中的第二句话,将传入指针倒回去内存控制块的大小,然后将该块中的is_available设置为1,将此空间标记为空闲空间,至于后续的回收整理,应该是操作系统和glibc内存管理模块来整理。从实现上看,释放的传入只能是分配内存块的首地址,而不能是中间的某个地址。

    从上述的free代码中来看,执行free函数后,堆上对应已分配内存已经标记为可用,但是这个可用内存空间经过多久才能被用户再次使用,这就取决于OS的内存管理策略,在还没将此块空间回收整理到空闲链表前,这块空间对用户来说,是不可用的。

 

参考资料:malloc和free的实现原理

             glibc的malloc-更多的改进

             glibc中malloc的详细解释

           

Technorati 标签: malloc 内存管理

从malloc中窥探Linux内存分配策略的更多相关文章

  1. Linux内存分配小结--malloc、brk、mmap【转】

    转自:https://blog.csdn.net/gfgdsg/article/details/42709943 http://blog.163.com/xychenbaihu@yeah/blog/s ...

  2. java中内存分配策略及堆和栈的比较

    Java把内存分成两种,一种叫做栈内存,一种叫做堆内存 在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配.当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间 ...

  3. 【java虚拟机序列】java中的垃圾回收与内存分配策略

    在[java虚拟机系列]java虚拟机系列之JVM总述中我们已经详细讲解过java中的内存模型,了解了关于JVM中内存管理的基本知识,接下来本博客将带领大家了解java中的垃圾回收与内存分配策略. 垃 ...

  4. JVM中内存分配策略及堆和栈的比较

    最近愈发对JVM底层的运行 原理产生了兴趣,遂查阅相关资料以备忘. 内存分配策略 根据编译原理的观点,程序运行时的内存分配,有三种策略,分别为静态的.堆式的.栈式的. 静态存储分配指的是在编译时就能确 ...

  5. CentOS的Redis内存分配策略配置

    安装了一主两从节点,启动之后发现有一个警告: 大概是说overcommit_memory设置成了0,在低内存环境下后台保存可能会失败,设置成1重启可解决. 然后,不太懂这个配置的含义,google一把 ...

  6. 深入理解Linux内存分配

    深入理解Linux内存分配 为了写一个用户层程序,你也许会声明一个全局变量,这个全局变量可能是一个int类型也可能是一个数组,而声明之后你有可能会先初始化它,也有可能放在之后用到它的时候再初始化.除此 ...

  7. Memcache 内存分配策略和性能(使用)状态检查

    前言: 一直在使用Memcache,但是对其内部的问题,如它内存是怎么样被使用的,使用一段时间后想看看一些状态怎么样?一直都不清楚,查了又忘记,现在整理出该篇文章,方便自己查阅.本文不涉及安装.操作. ...

  8. 【转载】Ogre的内存分配策略

    原文:Ogre的内存分配策略 读这个之前,强烈建议看一下Alexandrescu的modern c++的第一章关于policy技术的解释.应该是这哥们发明的,这里只是使用. 首先列出涉及到的头文件:( ...

  9. 《深入理解Java虚拟机》-----第3章 垃圾收集器与内存分配策略

    Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的“高墙”,墙外面的人想进去,墙里面的人却想出来. 3.1 概述 说起垃圾收集(Garbage Collection,GC),大部分人都把这 ...

随机推荐

  1. 在C++中使用golang的协程

    开源项目cpp_features提供了一个仿golang协程的stackful协程库. 可以在c++中使用golang的协程,大概语法是这样的: #include <iostream> v ...

  2. THD 变量存入threads中

    http://blog.csdn.net/gapaul/article/details/12047497 http://ourmysql.com/archives/930

  3. oracle的触发器

    oracle的触发器分为语句级和行级两种类型,在视图上所创建的触发器叫做什么类型的触发器? DML触发器有三类: 1, insert触发器: 2, update触发器: 3, delete触发器: 触 ...

  4. php与mysql的链接到底用mysql 还是mysqli,pdo

    参考:http://php.net/manual/en/mysqlinfo.api.choosing.php

  5. MySQL无视密码进入Server

    在[mysqld]的段中加上一句:skip-grant-tables 如下 [mysqld] skip-grant-tables 即可不输入密码就可以进入mysql server,然后就可以随便修改数 ...

  6. Foundation学习笔记

    . 链接:Foundation学习,代码实例总结(pdf版) .

  7. 1.6.4 Uploading Structured Data Store Data with the Data Import Handler

    1.使用DIH上传结构化数据 许多搜索应用索引结构化数据,如关系型数据库.DIH提供了一个这样的存储并索引结构化数据的机制.除了关系型数据库,solr可以索引来自HTTP的内容,基于数据源如RSS和A ...

  8. nodejs的mysql模块学习(六)连接池的创建和使用

    介绍 在 软件工程 , 连接池 是一个 高速缓存 的 数据库连接 维持,使得连接可以当需要将来向数据库请求重复使用. [ 来源请求 ] 连接池用于提高数据库上执行命令的性能. 打开并保持每个用户的数据 ...

  9. 自定义EditText实现一键删除数据

    转载请注明出处http://blog.csdn.net/xiaanming/article/details/11066685 自定义EditText带删除小图标, 实现的功能: 点击删除小图标,删除当 ...

  10. 【AR】Vuforia App key is missing.Please get a valid key

    在跑Vuforia 的sample android app 的时候报了下面这个错,找了半天才找到解决方法: "Vuforia App key is missing. Please get a ...