ptmalloc源码阅读-malloc_chunk

内存管理不外乎三个层面,用户管理层,C运行时库层,操作系统层
目前轮子处于运行时库层,制作这个轮子的目的是为了了解底层内存分配是如何实现的,后面肯定主要是实现用户管理层。
常见C内存管理程序:
Doug Lea Malloc:Doug Lea Malloc实际上是完整的一组分配程序,其中包括Doug Lea的原始分配程序,GNU libc分配程序和ptmalloc。Doug Lea的分配程序加入了索引,这使得搜索速度更快,并且可以将多个没有被使用的块组合为一个大的块。它还支持缓存,以便更快地再次使用最近释放的内存。ptmalloc是Doug Lea Malloc 的一个扩展版本,支持多线程。在本文后面的部分详细分析ptamlloc2的源代码实现。
BSD Malloc:BSD Malloc是随4.2 BSD发行的实现,包含在FreeBSD之中,这个分配程序可以从预先确实大小的对象构成的池中分配对象。它有一些用于对象大小的 size类,这些对象的大小为2的若干次幂减去某一常数。所以,如果您请求给定大小的一个对象,它就简单地分配一个与之匹配的size类。这样就提供了一个快速的实现,但是可能会浪费内存。
Hoard:编写Hoard的目标是使内存分配在多线程环境中进行得非常快。因此,它的构造以锁的使用为中心,从而使所有进程不必等待分配内存。它可以显著地加快那些进行很多分配和回收的多线程进程的速度。
TCMalloc:(Thread-Caching Malloc)是google开发的开源工具──“google-perftools”中的成员

目前主要通过阅读GNU的libc的ptmalloc来学习主流的内存管理

malloc_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;
   /* Only used for large blocks: pointer to next larger size.  */
  struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */
  struct malloc_chunk* bk_nextsize;
 };

glibc源码中有Colin Plumb作出的很详细的介绍。chunk的使用采用了一个“boundary tag”的方法ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps。重点理解chunk的复用。
一个空闲的块的存储结构如下:

chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    | Size of previous chunk|
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
`head:' | Size of chunk, in bytes |P|
  mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    | Forward pointer to next chunk in list |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    | Back pointer to previous chunk in list|
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    | Unused space (may be 0 bytes long).
    .   .
    .   |
nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
`foot:' | Size of chunk, in bytes   |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

每个free的chunk都是保存在一个双向链表,而所有的双向链表都保存在bin中,所以mem中会保存fp和bp。而每个chunk的开头会保存前一个free的chunk的size,紧接着的head会保存chunk的大小,但是最后一位p表示前面一个chunk是否被使用,置0表示没被使用。第一次分配是该位置1。
如果p位置1,则表示前一个chunk被使用了,则size of previou chunk没有任何意义,反而可以被前一个chunk利用来保存数据。fp和bp同样被复用。
则保存内容的块的结构如下:

chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    | Size of previous chunk, if allocated| |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    | Size of chunk, in bytes   |M|P|
  mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    | User data starts here...  .
    .   .
    . (malloc_usable_size() bytes)  .
    .   |
nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    | Size of chunk |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

在开始有一个声明(对size_t的处理):

#ifndef INTERNAL_SIZE_T
#define INTERNAL_SIZE_T size_t
#endif
...
/* The corresponding word size */
#define SIZE_SZ (sizeof(INTERNAL_SIZE_T))
 ... 
    struct malloc_chunk;
typedef struct malloc_chunk* mchunkptr;

紧接着 后面一块内容是对块的size和对齐的一系列处理:
因为malloc之后返回的指针为mem的起始地址,所以有对该地址与chunk地址的转换,由上面的结构表示可以明白下面的处理:

#define chunk2mem(p)   ((void*)((char*)(p) + 2*SIZE_SZ))
#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ))

每个chunk最小的大小:

#define MIN_CHUNK_SIZE(offsetof(struct malloc_chunk, fd_nextsize))

其中

#define offsetof(s, m)   (size_t)&(((s *)0)->m)

s是一个结构名,它有一个名为m的成员(s和m 是宏offsetof的形参,它实际是返回结构s的成员m的偏移地址.(s )0 是骗编译器说有一个指向类(或结构)s的指针,其地址值0。&((s )0)->m 是要取得类s中成员变量m的地址. 因基址为0,这时m的地址当然就是m在s中的偏移。最后转换size_t 型。
后面还有一些处理不细讲了,源码中都有很详细的注释。重点是要了解chunk的数据结构以及内存复用的思想。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本文通过Glibc的内存暴增问题,主要介绍了系统的内存管理问题,具体如下: 目录 1. 问题 2. 基础知识 2.1 X86平台Linux进程内存布局 2.1.1 32位模式下进程内存经典布局 2.1.2 32位模式下进程默认内存布局 2.1.3 64位模式下进程内存布局 2.2 操作系统内存分配的相关函数 2.2.1 Heap操作相关函数 2.2.2 Mmap映射区域操作相关函数 3. 概述 3.1 内存管理一般性描述 3.1.1 内存管理的方法 3.1.2 内存管理器的设计目标 3.1.3 常见C内存管理程序 3.2 Ptmalloc内存管理概述 3.2.1 简介 3.2.2 内存管理的设计假设 3.2.3 内存管理数据结构概述 3.2.4 内存分配概述 3.2.5 内存回收概述 3.2.6 配置选项概述 3.2.7 使用注意事项 4. 问题分析及解决 5. 源代码分析 5.1 边界标记法 5.2 分箱式内存管理 5.2.1 Small bins 5.2.2 Large bins 5.2.3 Unsorted bin 5.2.4 Fast bins 5.3 核心结构体分析 5.3.1 malloc_state 5.3.2 Malloc_par 5.3.3 分配区的初始化 5.4 配置选项 5.5 Ptmalloc的初始化 5.5.1 Ptmalloc未初始化时分配/释放内存 5.5.2 ptmalloc_init()函数 5.5.3 ptmalloc_lock_all(),ptmalloc_unlock_all(),ptmalloc_unlock_all2() 5.6 多分配区支持 5.6.1 Heap_info 5.6.2 获取分配区 5.6.3 Arena_get2() 5.6.4 _int_new_arena() 5.6.5 New_heap() 5.6.6 get_free_list()和reused_arena() 5.6.7 grow_heap(),shrink_heap(),delete_heap(),heap_trim() 5.7 内存分配malloc 5.7.1 public_mALLOc() 5.7.2 _int_malloc() 5.8 内存释放free 5.8.1 Public_fREe() 5.8.2 _int_free() 5.8.3 sYSTRIm()和munmap_chunk(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值