zoukankan      html  css  js  c++  java
  • customize your own memory allocator (2)

    I have made a more sophisticated version of memory allocator based on mmap. It can avoid memory increacement issue happened in traditional memory allocator, e.g. glibc malloc/free. However, it has two disadvantages. One of them is that this allocator is slower than glibc malloc/free since it call mmap/munmap frequently. The other one is that it does not support multi-threads.

    The source code is as following which may contain bugs, since I just did some simple tests, a random test. More test should be done before it really used to substitute glibc memory allocator.

    --------------------------------------------------------------------------------

    [torstan]$ more malloc.h

    #ifndef _MALLOC_MY_H
    #define _MALLOC_MY_H
    #include<stdio.h>

    #ifdef __cplusplus
    extern "C" {
    #endif

    void* malloc(size_t sz);
    void free(void *p);

    #ifdef __cplusplus
    }
    #endif

    #endif

    [torstan]$ more malloc.c

    #include "malloc.h"
    #include <sys/mman.h>

    #define BINNUM 8
    #define LARGEOBJ 1024
    #define PAGESIZE 4096
    #define PAGE_START(p) ((char*)(((size_t)(p))/PAGESIZE*PAGESIZE))
    #define DBG(x) {x}
    //#define DBG(x)

    struct _Item{
    struct _Item* next;
    };
    typedef struct _Item Item;

    struct _Mmap_alloc_header{
    void* saddr; //start address
    size_t nsize; //bytes of memory requested
    };
    typedef struct _Mmap_alloc_header Mmap_alloc_header;

    struct _Page_header{
    struct _Page_header* next; //next page
    size_t nsize; //size of chunk
    struct _Page_header* prev; //prev page
    Item* freelist; //free list in this page
    size_t nfree; //number of free chunks
    };
    typedef struct _Page_header Page_header;

    static size_t bin[BINNUM] = {8,16,32,64,128,256,512,1024};
    static Page_header* full_bin[BINNUM] = {0};
    static Page_header* free_bin[BINNUM] = {0};

    void* remove_head(Page_header** list)
    {
    Page_header* head = *list; //a copy of pointer
    Page_header* page = head;
    if(head->next)
    head->next->prev = 0;
    head = head->next;
    *list = head;
    return page;
    }

    void* remove_page(Page_header** list, Page_header* page) //remove page from list
    {
    Page_header* head = *list;
    Page_header* prev = page->prev;
    Page_header* next = page->next;
    if(head == page)
    return remove_head(list);
    if(prev)
    prev->next = next;
    if(next)
    next->prev = prev;
    page->next = page->prev = 0;
    return page;
    }

    void add_head(Page_header** list, Page_header* page) //add page to head of list
    {
    Page_header* head = *list;
    page->next = head;
    page->prev = 0;
    if(head)
    head->prev = page;
    head = page;
    *list = head;
    }

    int get_binsize(size_t sz)
    {
    int i = 0;
    if(sz > LARGEOBJ)
    return -1;
    if(sz <= bin[0])
    return 0;
    for(i=1;i<BINNUM;i++)
    {
    if(sz > bin[i-1] && sz<= bin[i])
    return i;
    }
    return -1;
    }

    void* allocate_page(int bid)
    {
    char* p;
    size_t i, n = bin[bid], num = (PAGESIZE - sizeof(Page_header))/n;
    char* page = (char*)mmap(NULL, PAGESIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
    if(bid < 0 || bid >= BINNUM) return 0;
    if(page == MAP_FAILED || !page) return 0;
    Page_header* header = (Page_header*)page;
    header->next = 0;
    header->prev = 0;
    header->nfree = num;
    header->nsize = n;
    header->freelist = (Item*)(page + sizeof(Page_header));
    add_head(&free_bin[bid], header);
    //build a list from the free chunks
    p = (char*)(header->freelist);
    for(i=0;i<num;i++)
    {
    Item* item = (Item*)p;
    item->next = (Item*)(p + n);
    p += n;
    }
    Item* lastitem = (Item*)(p-n);
    lastitem->next = 0;

    return page;
    }

    void* smallobj_malloc(size_t sz)
    {
    int bid;
    void* p;
    Item* item;
    Page_header* page;
    if(sz > LARGEOBJ) return NULL;
    bid = get_binsize(sz);
    if(bid < 0 || bid >= BINNUM)
    return 0;
    if(!free_bin[bid])
    {
    char* q = (char*)allocate_page(bid);
    if(!q)
    {
    printf("error: no page allocated\n");
    return 0;
    }
    }
    page = free_bin[bid];
    p = page->freelist;
    item = page->freelist;
    page->freelist = item->next;
    page->nfree--;
    if(!free_bin[bid]->freelist || page->nfree == 0) //remove current page from free_bin, and add it to full_bin
    {
    Page_header* p2 = (Page_header*)remove_head(&free_bin[bid]);
    add_head(&full_bin[bid], p2);
    }
    return p;
    }

    void smallobj_free(void* p)
    {
    char* page_start = PAGE_START(p);
    Mmap_alloc_header* phead = (Mmap_alloc_header*)page_start;
    Page_header* page = (Page_header*)page_start;
    size_t n = phead->nsize;
    Item* item = (Item*)p;
    int bid = get_binsize(n);
    if(bid < 0 || bid >= BINNUM) return;
    if(n > LARGEOBJ) return;

    item->next = page->freelist; //add to head of free list
    page->freelist = item;
    page->nfree ++;
    if(page->nfree == (PAGESIZE - sizeof(Page_header))/page->nsize)
    {
    remove_page(&free_bin[bid], page);
    munmap(page_start, PAGESIZE);
    }
    }

    void* largeobj_malloc(size_t sz)
    {
    if (sz <= 0) return NULL;
    size_t len = sz + sizeof(Mmap_alloc_header);
    char* p = (char*)mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
    if(p == MAP_FAILED || !p){
    printf("failed in mmap!\n");
    return NULL;
    }

    Mmap_alloc_header *phead = (Mmap_alloc_header*)p;
    phead->saddr = p;
    phead->nsize = sz;

    return (void*)(p + sizeof(Mmap_alloc_header));
    }

    void largeobj_free(void* p)
    {
    if(p == NULL) return;
    Mmap_alloc_header* phead = (Mmap_alloc_header*)((char*)p - sizeof(Mmap_alloc_header));
    munmap(phead->saddr, phead->nsize + sizeof(Mmap_alloc_header));
    }

    void* malloc(size_t sz)
    {
    void *p=0;
    if(sz > LARGEOBJ)
    p = largeobj_malloc(sz);
    else
    p = smallobj_malloc(sz);

    DBG(printf("%p: allocate mem size %lu\n", p, sz);)
    return p;
    }

    void free(void* p)
    {
    char* page_start = PAGE_START(p);
    Mmap_alloc_header* phead = (Mmap_alloc_header*)page_start;
    size_t n = phead->nsize;
    if(n > LARGEOBJ)
    largeobj_free(p);
    else
    smallobj_free(p);
    DBG(printf("%p: free mem\n", p);)
    }

    ---------------------------------------------------------------------------------

    Testing:

    [torstan]$ LD_PRELOAD=./libmymalloc.so ./a.out
    malloc size 1, return 0x2a95659028
    malloc size 2, return 0x2a95659030
    malloc size 4, return 0x2a95659038
    malloc size 8, return 0x2a95659040
    malloc size 10, return 0x2a9565b028
    malloc size 20, return 0x2a9565c028
    malloc size 16, return 0x2a9565b038
    malloc size 1000, return 0x2a9565d028
    malloc size 1023, return 0x2a9565d428
    malloc size 1024, return 0x2a9565d828
    malloc size 2000, return 0x2a9565e010

    free size 1, at 0x2a95659028
    free size 2, at 0x2a95659030
    free size 4, at 0x2a95659038
    free size 8, at 0x2a95659040
    free size 10, at 0x2a9565b028
    free size 20, at 0x2a9565c028
    free size 16, at 0x2a9565b038
    free size 1000, at 0x2a9565d028
    free size 1023, at 0x2a9565d428
    free size 1024, at 0x2a9565d828
    free size 2000, at 0x2a9565e010

    ---------------

    random test code

    [torstan]$ more randomtest.cc
    #include<iostream>
    #include<vector>
    #include<cstdlib>
    using namespace std;

    int main()
    {
    int N=10000;
    vector<int*> v;
    v.reserve(N);
    for(int i=0;i<N;i++)
    {
    v.push_back(0);
    }

    for(int i=0;i<N;i++)
    {
    int n = rand()%N;
    int *p = v[n];
    if(p == 0)
    {
    int sz = rand()%3000;
    v[n] = new int[sz];
    }
    else
    {
    delete []p;
    v[n] = 0;
    }
    }

    for(int i=0;i<N;i++)
    {
    int *p = v[i];
    if(p)
    {
    delete []p;
    p = 0;
    }
    }

    return 0;
    }

    [tli@bclnx64 memoryStudy]$ grep allocate testres | wc -l
    7129
    [tli@bclnx64 memoryStudy]$ grep free testres | wc -l
    7129
    [tli@bclnx64 memoryStudy]$ tail testres
    0x2a97400010: free mem
    0x2a9736e010: free mem
    0x2a95da1010: free mem
    0x2a95ee8010: free mem
    0x2a96fd3010: free mem
    0x2a967a3010: free mem
    0x2a958b7010: free mem
    0x2a962a8010: free mem
    0x2a9609a010: free mem
    0x2a95659010: free mem

  • 相关阅读:
    集合:HashMap原理
    监控管理
    jvm(内存分配和回收策略、字节码执行引擎、运行时栈的结构)
    jvm:收集器
    多线程(线程的四种创建方式)
    scrapy之下载器中间件(Download Middleware)
    scrapy之Spider
    Scrapy之原理&提取数据
    小程序之请求服务器资源注意问题
    小程序之页面跳转
  • 原文地址:https://www.cnblogs.com/Torstan/p/2580017.html
Copyright © 2011-2022 走看看