转载:http://www.cppblog.com/yangfan/archive/2012/09/25/117132.html

1. Doug Lea malloc简介

Doug Lea malloc是一个用C语言实现的非常流行的内存分配器,由纽约州立大学Oswego分校计算机系教授Doug Lea于1987年撰写,许多人将其称为Doug Lea的malloc,或者简称dlmalloc,目前最新版本为2.8.4。

由于具备高效且占用空间较小等特点,dlmalloc被广泛使用,用Doug Lea自己的话说,就是“它在一些linux版本里面作为默认的malloc被使用,被编译到一些公共的软件包里,并且已经被用于各种PC环境及嵌入式系统,以及许多甚至我也不知道的地方”。

dlmalloc的由来,从Doug Lea自己写的文章看,似乎是这样的:1986年到1991年Doug Lea是libg++(即GNU C++ library)的主要作者,当时他写了大量有着动态分配内存的C++程序,结果发现程序跑得比预期慢,内存消耗也比预想的要大很多,追究下去,发现是所在系统内存分配器的问题。于是开始用C++为新类写一些特殊用途的分配器,但他很快意识到这并非一个好的策略,应该提供一个在C++和C环境下都能运行得很好的通用内存分配器,于是dlmalloc诞生了。在之后的日子里,Doug Lea和一些志愿者一直都在不断的维护优化这个内存分配器。dlmalloc之所以能被广泛应用,与其高标准的追求和不断的精益求精应该有着不可分割的关系。

另外,值得一提的是,Doug Lea是JAVA编程界的大师级人物,也是JCP中的一员。同时Doug还是一个无私的人,苹果越分越少,知识却越分越多,他深信知识的分享能激荡出不一样的火花。

本文以dlmalloc-2.6.6为分析对象,之所以选择这个版本而不是最新的版本,原因如下,一是公司项目操作系统用的是eCos,而eCos用的是dlmalloc-2.6.6;二是网友lenky0401已经很详细的分析了dlmalloc-2.8.3(见“参考文档”一节)。另外一个顺带的好处就是,通过两个版本的比较,可以找到从2.6.6到2.8.3的变迁及其缘由。

尽管dlmalloc经历了诸多版本的变化,然而malloc算法的两个核心元素一直没变:边界标记和分箱管理。

2.边界标记

在继续深入之前,有必要解释一下chunk的概念,这个概念对内存分配器而言十分重要。

chunk,“大块”的意思,在dlmalloc中指包含了用户空间、heap控制信息空间及出于对齐需求而多出来的空间的内存空间,是dlmalloc分配释放的基本操作对象。

有两种类型的chunk,已分配的chunk和未分配的chunk,两者交错排列,占据了整个heap空间。注意,没有相邻的两个未分配chunk,因为在调用free()释放被使用过的chunk时,dlmalloc将合并任何相邻的空闲chunk。交错的两种chunk看起来像这样

图1

Dlmalloc使用双向链表来管理空闲chunk,其节点数据结构体定义如下,

struct malloc_chunk

{

INTERNAL_SIZE_T prev_size;       /* Size of previous chunk (if free). */

INTERNAL_SIZE_T size;           /* Size in bytes, including overhead. */

struct malloc_chunk* fd;          /* double links -- used only if free. */

struct malloc_chunk* bk;

};

成员prev_size记录了物理位置上相邻的前一个chunk的大小,利用prev_size可以找到前一个chunk,这在free( )时合并前一个空闲块时派上了用场;

成员size记录了该chunk的大小,dlmalloc在32位处理器上总是8字节对齐,故size的低三位对size而言是无效的,dlmalloc利用这三位来记录一些信息,具体如下:

#define PREV_INUSE 0x1

bit[0]:物理位置上相邻的前一个chunk是否被分配使用的标志,如果为0x1,说明被分配;

#define IS_MMAPPED 0x2

bit[1]:如果为0x1,则表明该chunk通过mmap( )分配而得,那么在释放时调用munmap( );

fd和bk则分别指向双向链表中前一个节点和后一个节点。

其物理布局看起来像这样:

图2

可以看出,chunk指针指向heap内部控制信息,图中head和foot区域的Size of chunk必须是一样的,如此nextchunk才能根据Size of chunk准确找到chunk的位置。

另一种是已分配的chunk,其结构体和未分配chunk结构体一样,只是不会使用fd和bk两个成员,因为被分配后已经不需要这两个域了,其物理布局看起来像下图,chunk指后面8字节的偏移处,即mem区域,是返回给用户的内存指针,该chunk的heap控制信息占据了8个字节,

图3

在调用malloc( )时首先会将用户申请的size转换为系统可用的size,

#define request2size(req) \

(((long)((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) < \

(long)(MINSIZE + MALLOC_ALIGN_MASK)) ? MINSIZE : \

(((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) & ~(MALLOC_ALIGN_MASK)))

在32位处理器上等同下列表达式,

#define request2size(req) \

(((long)((req) + (0x4 + 0x7)) < \

(long)(0x10 + 0x7)) ? ((0x10 + 0x7) & ~(0x7)) : \

(((req) + (0x4 + 0x7)) & ~(0x7)))

从这个宏定义中,我们可以获取三点信息:

一是系统可用的size和用户申请的size的差值,最小是0x4;

二是系统可用的size最小为16个字节,即sizeof(malloc_chunk);

三是系统可用的size 8字节对齐;

说到这,或许你已经发现一个问题了,如果用户申请20个字节的空间,姑且称之为A,系统会分配24字节,而chunk的heap控制信息占了8个字节,那留给用户使用的只剩下18个字节了。如此看来,岂不是会覆盖下一个chunk(姑且称之为B)的“Size of previous chunk”区域?

这个问题问得好,学而思,而后得解,我们才能更加充分认识到这个设计的思想。为解答这个问题,我们先了解什么时候需要定位前一个chunk?只有在释放一块空间,判断前一个chunk是否空闲时才需要该动作。换而言之,当一个chunk被分配使用时,它根本不需要下一个chunk被释放时来合并它,既然不需要,就利用起来吧。于是,B的“Size of previous chunk”区域也被纳入到A的用户空间中了。

图4

从这一点讲,上图中的“Size of previous chunk, if allocated”的表述是不对的,应该是“Size of previous chunk, if freed”。

我曾分配了大小为0x98c的一块空间, 打印出来的控制信息证明了我的观点。

图5

Size of previous chunk域为0x0,属于上一个chunk的用户空间;

Size of chunk为0x991,bit[0]=0x1说明上一个chunk被分配使用,0x990是该chunk的大小,加上nextchunk的Size of previous chunk域4个字节,总共0x994,刚好比用户申请的0x98c多出8个字节;

Nextchunk的Size of chunk域为0x607f,0x607e为nextchunk的大小,bit[0]=0x1表明上一个chunk被分配使用。

转载于:https://www.cnblogs.com/DF11G/p/9037788.html

heap 内存管理 dlmalloc相关推荐

  1. 一文搞懂栈(stack)、堆(heap)、单片机裸机内存管理malloc

    大家好,我是无际. 有一周没水文了,俗话说夜路走多了难免遇到鬼. 最近就被一个热心网友喷了. 说我的文章没啥营养,所以今天来一篇烧脑的. 哈哈,开个玩笑,不要脸就没人能把我绑架. 主要是最近研发第二代 ...

  2. (深入理解计算机系统) bss段,data段、text段、堆(heap)和栈(stack)(C/C++存储类型总结)(内存管理)

    文章目录 bss段 data段 text段 堆(heap) 栈(stack) 一个程序本质上都是由 bss段.data段.text段三个组成的. 存储类型总结 bss段 bss段(bss segmen ...

  3. Windows内存管理 - 隐藏在new和malloc背后的heap

    先来说,heap是什么,heap就是堆,在不知道具体细节的时候,我们只知道,通过new和malloc,我们可以动态获得一个内存区域,用来存放自己的对象和变量,而这些内存区域都是在heap上的.heap ...

  4. linux内存管理之 ION 内存管理器浅析Ⅰ(system heap)

    目录 1 什么是ION 2 ION中不同 type 的 heap 3 ION分配(以system heap为例) 3.1 ion_alloc() 3.2 ion_system_heap_allocat ...

  5. linux内存管理之 ION 内存管理器浅析Ⅱ(system contig heap)

    目录 1 system contig heap 与 system heap 2 system contig heap创建 3 system contig heap内存分配 4 system conti ...

  6. Linux堆内存管理深入分析(上)

    Linux堆内存管理深入分析 (上半部) 作者:走位@阿里聚安全   0 前言 近年来,漏洞挖掘越来越火,各种漏洞挖掘.利用的分析文章层出不穷.从大方向来看,主要有基于栈溢出的漏洞利用和基于堆溢出的漏 ...

  7. Linux堆内存管理深入分析

    0 前言 近年来,漏洞挖掘越来越火,各种漏洞挖掘.利用的分析文章层出不穷.从大方向来看,主要有基于栈溢出的漏洞利用和基于堆溢出的漏洞利用两种.国内关于栈溢出的资料相对较多,这里就不累述了,但是关于堆溢 ...

  8. Linux glibc内存管理:用户态内存分配器——ptmalloc实现原理

    文章目录 ptmalloc 设计假设 Arena Chunk Bins 内存分配.释放流程 总结 C++ STL : SGI-STL空间配置器源码剖析 Linux 内存管理 | 物理内存管理:物理内存 ...

  9. davlik虚拟机内存管理之一——内存分配

    dalvik虚拟机是Google在Android平台上的Java虚拟机的实现,内存管理是dalvik虚拟机中的一个重要组件. 从概念上来说,内存管理的核心就是两个部分:分配内存和回收内存.Java语言 ...

最新文章

  1. Dubbo中基于权重的随机算法
  2. python3读取excel数据-Python3操作Excel文件(读写)的简单实例
  3. 为什么我们会拖延? (TED)
  4. 1、RN跨平台开发——环境搭建
  5. 18 4Sum(寻找四个数之和为指定数的集合Medium)
  6. Android-LayoutInflater
  7. java21天打卡Day13-正则表达式
  8. 我的一个低级错误,导致数据库崩溃半小时!!
  9. mathml解析引擎MathPlayer的缺陷
  10. c语言怎样找无限循环小数的循环体
  11. yoloV3运行速度测试报告
  12. 牛客网 月出皎兮,佼人僚兮。 树上启发式合并
  13. 电子书极其格式的相关知识
  14. 关于量子领域的一些概念
  15. 小米无线键盘的连接方式
  16. arctanx麦克劳林公式推导过程_半桥 LLC 基波分析和参数计算过程推导
  17. TXLINE 这个软件 计算 微带线的宽度
  18. 调用函数,求加减乘除(基础)。
  19. 主流操作系统的开发语言
  20. office972003_Microsoft Office Word 97-2003 文档

热门文章

  1. eMMC Mandatory Boot和Alternative Boot
  2. MySQL锁:全局锁、表级锁和行锁
  3. The road you are trudging is bound for loneliness.(前行的道路注定孤独)
  4. 带宽-服务器测速(Speedtest)
  5. java rollback_Java Connection.rollback()方法:事务回滚
  6. 在word插入钢筋符号
  7. 解决GitHub报错You‘re using an RSA key with SHA-1, which is no longer allowed. Please use a newer client
  8. WindowManager
  9. 括号画家——解题报告
  10. 读《孙悟空是个好员工》有感(2005-5-23)