glibc下malloc的理解

来源:互联网 发布:oracle数据库基础教程 编辑:程序博客网 时间:2024/05/21 19:46

0.1 简介

在linux中常见的malloc是glibc的malloc,经对glibc上malloc修改有适用于linux多线程的mallocdlmalloc,还有一个ptmalloc2这两者有区别,其区别在于:

dlmalloc 在子线程和父线程同时调用malloc时会有竞争,且只会有一个能够从heap中分配到空间。并且freelist data structure 是被众进程共享的。

ptmalloc2 可以确保不有这种竞争,而且freelist 是各自进程独享自己的一个结构体。ptmalloc是per thread malloc之意。


1.malloc用例

/* Per thread arena example. */#include <stdio.h>#include <stdlib.h>#include <pthread.h>#include <unistd.h>#include <sys/types.h>void* threadFunc(void* arg) {        printf("Before malloc in thread 1\n");        getchar();        char* addr = (char*) malloc(1000);        printf("After malloc and before free in thread 1\n");        getchar();        free(addr);        printf("After free in thread 1\n");        getchar();}int main() {        pthread_t t1;        void* s;        int ret;        char* addr;        printf("Welcome to per thread arena example::%d\n",getpid());        printf("Before malloc in main thread\n");        getchar();        addr = (char*) malloc(1000);        printf("After malloc and before free in main thread\n");        getchar();        free(addr);        printf("After free in main thread\n");        getchar();        ret = pthread_create(&t1, NULL, threadFunc, NULL);        if(ret)        {                printf("Thread creation error\n");                return -1;        }        ret = pthread_join(t1, &s);        if(ret)        {                printf("Thread join error\n");                return -1;        }        return 0;}

情景1

main threadmalloc之前

sploitfun@sploitfun-VirtualBox:~/ptmalloc.ppt/mthread$ ./mthread Welcome to per thread arena example::6501Before malloc in main thread...sploitfun@sploitfun-VirtualBox:~/ptmalloc.ppt/mthread$ cat /proc/6501/maps08048000-08049000 r-xp 00000000 08:01 539625   /home/sploitfun/ptmalloc.ppt/mthread/mthread08049000-0804a000 r--p 00000000 08:01 539625   /home/sploitfun/ptmalloc.ppt/mthread/mthread0804a000-0804b000 rw-p 00001000 08:01 539625   /home/sploitfun/ptmalloc.ppt/mthread/mthreadb7e05000-b7e07000 rw-p 00000000 00:00 0 

再未用malloc时,尚未分配heap

情景2

sploitfun@sploitfun-VirtualBox:~/ptmalloc.ppt/mthread$ ./mthread Welcome to per thread arena example::6501Before malloc in main threadAfter malloc and before free in main thread...sploitfun@sploitfun-VirtualBox:~/lsploits/hof/ptmalloc.ppt/mthread$ cat /proc/6501/maps08048000-08049000 r-xp 00000000 08:01 539625   /home/sploitfun/ptmalloc.ppt/mthread/mthread08049000-0804a000 r--p 00000000 08:01 539625   /home/sploitfun/ptmalloc.ppt/mthread/mthread0804a000-0804b000 rw-p 00001000 08:01 539625   /home/sploitfun/ptmalloc.ppt/mthread/mthread0804b000-0806c000 rw-p 00000000 00:00 0          [heap]b7e05000-b7e07000 rw-p 00000000 00:00 0 

使用malloc后即在0x084b000~0x086c000 开辟一个heap。虽然源码中要分配1000字节,但这里分配了132k,这是预先分配出一块内存专门给malloc用,这样以后再有malloc就直接从这块区域中在分配了,其中这块区域以brk来活动地分配heap的界限。
addr = (char*) malloc(1000);

情景3

当运行了free 之后,heap区并未释放给os,这是一种策略,当再次malloc时再从这里分配,当若干时间后,才会降低brk值来减小top层的无用的chunk。

sploitfun@sploitfun-VirtualBox:~/ptmalloc.ppt/mthread$ ./mthread Welcome to per thread arena example::6501Before malloc in main threadAfter malloc and before free in main threadAfter free in main thread...sploitfun@sploitfun-VirtualBox:~/lsploits/hof/ptmalloc.ppt/mthread$ cat /proc/6501/maps08048000-08049000 r-xp 00000000 08:01 539625    home/sploitfun/ptmalloc.ppt/mthread/mthread08049000-0804a000 r--p 00000000 08:01 539625    home/sploitfun/ptmalloc.ppt/mthread/mthread0804a000-0804b000 rw-p 00001000 08:01 539625    home/sploitfun/ptmalloc.ppt/mthread/mthread0804b000-0806c000 rw-p 00000000 00:00 0          [heap]b7e05000-b7e07000 rw-p 00000000 00:00 0 

情景4

当运行到thread1子线程时,子线程会分配其stack,但此时尚未分配子线程的heap

sploitfun@sploitfun-VirtualBox:~/ptmalloc.ppt/mthread$ ./mthread Welcome to per thread arena example::6501Before malloc in main threadAfter malloc and before free in main threadAfter free in main threadBefore malloc in thread 1...sploitfun@sploitfun-VirtualBox:~/ptmalloc.ppt/mthread$ cat /proc/6501/maps08048000-08049000 r-xp 00000000 08:01 539625   /home/sploitfun/ptmalloc.ppt/mthread/mthread08049000-0804a000 r--p 00000000 08:01 539625   /home/sploitfun/ptmalloc.ppt/mthread/mthread0804a000-0804b000 rw-p 00001000 08:01 539625   /home/sploitfun/ptmalloc.ppt/mthread/mthread0804b000-0806c000 rw-p 00000000 00:00 0          [heap] 具有读写权限b7604000-b7605000 ---p 00000000 00:00 0 **b7605000-b7e07000 rw-p 00000000 00:00 0          [stack:6594]**

情景5

子线程中malloc情景,子线程的heap创建用的是mmap系统调用,而不是mainthread中用的sbrk系统调用。当申请超过128k时会用mmap而不是sbrk,但这里只申请了1k啊(?)
(那么malloc究竟是怎么选择系统调用的呢?)

总共mmap的1M数据从0xb7500000~0xb7600000 但是只是前132k具有读写权限。可以使heap

sploitfun@sploitfun-VirtualBox:~/ptmalloc.ppt/mthread$ ./mthread Welcome to per thread arena example::6501Before malloc in main threadAfter malloc and before free in main threadAfter free in main threadBefore malloc in thread 1After malloc and before free in thread 1...sploitfun@sploitfun-VirtualBox:~/ptmalloc.ppt/mthread$ cat /proc/6501/maps08048000-08049000 r-xp 00000000 08:01 539625   /home/sploitfun/ptmalloc.ppt/mthread/mthread08049000-0804a000 r--p 00000000 08:01 539625   /home/sploitfun/ptmalloc.ppt/mthread/mthread0804a000-0804b000 rw-p 00001000 08:01 539625   /home/sploitfun/ptmalloc.ppt/mthread/mthread0804b000-0806c000 rw-p 00000000 00:00 0          [heap]b7500000-b7521000 rw-p 00000000 00:00 0          只有132k具有读写权限b7521000-b7600000 ---p 00000000 00:00 0 b7604000-b7605000 ---p 00000000 00:00 0 b7605000-b7e07000 rw-p 00000000 00:00 0          [stack:6594]

情景6

当子线程free时,其heap并未释放给os。

sploitfun@sploitfun-VirtualBox:~/ptmalloc.ppt/mthread$ ./mthread Welcome to per thread arena example::6501Before malloc in main threadAfter malloc and before free in main threadAfter free in main threadBefore malloc in thread 1After malloc and before free in thread 1After free in thread 1...sploitfun@sploitfun-VirtualBox:~/ptmalloc.ppt/mthread$ cat /proc/6501/maps08048000-08049000 r-xp 00000000 08:01 539625   /home/sploitfun/ptmalloc.ppt/mthread/mthread08049000-0804a000 r--p 00000000 08:01 539625   /home/sploitfun/ptmalloc.ppt/mthread/mthread0804a000-0804b000 rw-p 00001000 08:01 539625   /home/sploitfun/ptmalloc.ppt/mthread/mthread0804b000-0806c000 rw-p 00000000 00:00 0          [heap]b7500000-b7521000 rw-p 00000000 00:00 0 b7521000-b7600000 ---p 00000000 00:00 0 b7604000-b7605000 ---p 00000000 00:00 0 b7605000-b7e07000 rw-p 00000000 00:00 0          [stack:6594]

2.terminology

arena的大小:

与cpu的核数有关;

32-bit系统 : 2*cpu_core_num64-bit系统 : 8*cpu_core_num

multi-arena多线程的共享:

假如某个app有4个线程:main thread和thread1、thread2以及thread3。跑在32bit的1核cpu上。经计算可以有2个arena。肯定是不够一一对应的,随意需要共享:

main thread 首先创建自己的arena,无竞争
thread1、thread2创建自己的arena,无竞争(??)
thread3需要竞争

会从所有的arena中轮训获得lock,如果获得了,就占有执行。
否则的话需要等待lock
当main thread和thread3共享一个arena时,这两个线程就实现了共享。

数据结构

struct smem_heap_info {    unsigned initialized;    unsigned free_offset;    unsigned heap_remaining;    unsigned reserved;};struct smem_heap_info heap_info;

每一个thread arena含有multi-heaps,每一个heap都有这个heap_info头,因为在thread arena中,每个thread最开始都仅有一个heap,当该thread有过多的malloc,超过这个初始的heap时,需要从thread arena中再找一个heap。

fine MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD)struct malloc_state {  binmap_t   smallmap;  binmap_t   treemap;  size_t     dvsize;  size_t     topsize;  char*      least_addr;  mchunkptr  dv;  mchunkptr  top;  size_t     trim_check;  size_t     release_checks;  size_t     magic;  mchunkptr  smallbins[(NSMALLBINS+1)*2];  tbinptr    treebins[NTREEBINS];  size_t     footprint;  size_t     max_footprint;  size_t     footprint_limit; /* zero means no limit */  flag_t     mflags;#if USE_LOCKS  MLOCK_T    mutex;     /* locate lock among fields that rarely change */#endif /* USE_LOCKS */  msegment   seg;  void*      extp;      /* Unused but available for extensions */  size_t     exts;};

arena header 一组heaps公用一个arena header。

struct malloc_chunk {  size_t               prev_foot;  /* Size of previous chunk (if free).  */  size_t               head;       /* Size and inuse bits. */  struct malloc_chunk* fd;         /* double links -- used only if free. */  struct malloc_chunk* bk;};

细化heap,每个heap中又细分为多个chunk,每个chunk都有自己的chunk header

main thread的arena是没有多heaps的,因此没有heap_info。不像有heaps的子线程arena,子线程的某个thread的用完其初始heap时,如果还要malloc,那么就会从arena中在获得一个heap。而main thread是没有heaps的,当main的malloc超过了其arena界限时,需要从新设置brk()
main thread和子系统arena中heap和chunks的分部
左边是main thread arena 它是没有heaps的只有chunks,如果分配越界需要重新设置brk来得到更多的arena。右边是子线程的arena ,它包含多个heaps,每个都有heap_info,这里是其一个heap,heap_info中可以找到其chunks。最开始子线程thread1会分配到一个heap,当其分配越界了就会从子线程的arena中再获得一个heap。下图是子系统多heaps的情况
多heaps的


chunk

从上面可以看到有allocated_chunk、malloc_chunk、free_chunk和top_chunk。
allocated_chunk和free_chunk的结构

对于allocated_chunk,含preb_size、size、mem和next_chunk。
这里写图片描述
其中n、m、p分表表示:

item meaning n non_main_arena 置位后为thread的arena m is_mmaped 置位,该chunk是mmap的 p prev_inuse 当前一个chunk是allocated_chunk时,该位置位。

bin

bin是freelist的对chunk size进行管理的一个数据结构,根据不同chunk size来划分不同的bin。

item details chunk feature malloc和free过程 fast bin 用fastbinsY这个数组来包含它,数组的元素是fastbin 由16~80字节的chunk组成,在众多bins中,fastbin的allocate和deallocate是最快的;每个fastbin会有一个10个bin,这10个bin组成一个链表,该链表确保对fastbin类型的bin的添加和删除都发生在链表头和链表尾,避免链表中间的几个chunk被释放掉;在每个fastbin类型的bin中又有1个chunk链表,index是0的bin的chunk链表中chunk的size是16字节,index是1的bin的chunk链表中chunk的size是24字节,依次叠加8字节;在最开始初始化的fast bin中,其最大的size是64字节而不是80字节;在fastbin中相邻的free的chunk不会merge到一起,虽然有碎片但是却提升了速度。 malloc一个fastbin类型时,最开始从smallbin获得。 unsorted bin bin1 chunk的size无限制,unsortedbin含有两个双向链表;情景是,当small chunk被释放,他们会加到unsortedbin的链表中 small bin bin2~bin63 chunk size小于512的都是smallbin,在分配时比largebin快比fastbin慢;一个samllbin素组中含有62个smallbin元素,采用双向循环链表;每个smallbin元素含有一组同等大小的chunk,每个smallbin元素的chunk大小按8字节递增。如果相邻的chunk都是free的则把这些chunk合并到一起。 large bin bin64~bin126
=512的chunk,包含这些chunk的bin叫largebin;largebin数组有63个largebin成员,每一个largebin元素含有一个双向链表;这63个largebin的划分是:32个largebin的chunksize是按64字节叠加的,16个是按512叠加,8个4096字节,4个32768字节,2个262144字节,1个largebin元素是remaining size。相邻的free chunk会合并。

fastbin diagram
unsortedbin diagram


特殊的chunk

item details top_chunk 在边界顶端的chunk,不属于任何bin。他是一种后备军,当其他的bin无资源再满足用户请求的时候,top_chunk就会顶上去供其使用,可以供任何类型的bin使用。 last_remainder_chunk 当我们要比较小的内存时,且smallbin和usortedbin无法满足时,就会从比较大的chunk中分裂出来一满足用户请求,剩下的那部分就是last_remainder_chunk,这个last_remainder_chunk会添加到unsortedbin的链表中。

https://sploitfun.wordpress.com/2015/02/10/understanding-glibc-malloc/comment-page-1/

0 0