最佳适配内存分配算法(二)

来源:互联网 发布:淘宝乐器 编辑:程序博客网 时间:2024/06/03 21:37
最佳适配内存分配算法(二)
上次的blog
http://blog.csdn.net/leeshuheng/article/details/6736194
中的代码对最佳适配内存分配算法做了简单的演绎。
由于现实中程序经常分配小内存块,且常常重复分配和释放相同
大小的内存块,所以下面的代码对上述blog中代码做了如下优化,
具体内容请看后面的代码:
1. 每次free内存后,并未马上将其和临近的空闲
   内存合并,而是直接插入bin中。直到free的
   调用次数达到某个值,才进行内存块合并,这时
   只合并大内存块;
2. 当由于没有大的空闲内存块而无法满足内存分配时,
   进行空闲内存块合并,包括大内存块和小内存块
   的合并;
3. 对大空闲块和小空闲块的查找做了不同处理;
4. 对锁进行了重新设计;


由于只是用于实验的原型代码,所以下面的代码存在如下问题:
1.对多进程和多线程支持的不好。
2.mem_alloc返回的是内存的偏移,而不是指针。
  这主要是考虑了对共享内存的分配。
3.内存块散列的不好,大约有20个槽总是空的。
4.代码没经过仔细编写。许多代码是临时写的。
  整个main.c中代码都是临时拼凑的。
  代码显得凌乱,程序有bug。
5.还存在其他问题。


代码并未真正分配内存,只是在已分配的内存上作切割,是个
池式共享内存分配器。
代码在fedora 11上做了简单的测试。


编译: 使用make
执行: ./mytest 1
停止: Ctrl-C

下面是代码:

mem_alloc.h:
===========================================================
// 2011年 08月 24日 星期三 09:10:32 CST
// author: 李小丹(Li Shao Dan) 字殊恒(shuheng)
// K.I.S.S
// S.P.O.T

#ifndef MEM_ALLOC_H
#define MEM_ALLOC_H

#include <sys/ipc.h>

//#define SINGLE_PROCESS

#ifdef __cplusplus
extern "C" {
#endif

struct mem_info;

struct mem_info *mem_link_shm(key_t, size_t, int);
int mem_detach_shm(struct mem_info *);
struct mem_info *mem_init(void *, unsigned long, int);
void mem_destroy(struct mem_info *);
unsigned long mem_alloc(struct mem_info *, unsigned long);
void mem_free(struct mem_info *, unsigned long);
unsigned long mem_ptr_2_off(struct mem_info *, void *);
void *mem_off_2_ptr(struct mem_info *, unsigned long);

#ifdef __cplusplus
}
#endif

#endif
===========================================================

mem_alloc.c:
===========================================================
// 2011年 08月 24日 星期三 09:19:52 CST
// author: 李小丹(Li Shao Dan) 字 殊恒(shuheng)
// K.I.S.S
// S.P.O.T

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include <sys/shm.h>

#include "mem_alloc.h"
//#include "futex.h"
#include "mem_lock.h"

#ifdef SINGLE_PROCESS

#pragma message "not use lock"

#undef mem_lock_init
#undef mem_lock_lock
#undef mem_lock_unlock
//#undef futex_create
#define mem_lock_init(x)
#define mem_lock_lock(x)
#define mem_lock_unlock(x)
//#define futex_create(x)

#endif

#define BIN_NUMBER 128UL
#define BIN_SMALL_THRESHOLD 64
#define SIZE_SMALL_THRESHOLD 512UL
#define BIN_SIZE \
    (unsigned long)(BIN_NUMBER * sizeof(unsigned long))
//#define LOW_SIZE (BIN_SIZE + sizeof(futex_t))
#define LOW_SIZE (BIN_SIZE + sizeof(mem_lock_t))
#define SMALLEST_SIZE \
    ((unsigned long)(sizeof(unsigned long) << 2))

#define CHAR_BIT_SHIFT 3
#define BIGBIN_SHIFT 8U

#define SMALL_SIZE_2_INDEX(x) (x >> CHAR_BIT_SHIFT)

#define BIG_SIZE_2_INDEX(s, i) \
{\
    unsigned long x = s >> BIGBIN_SHIFT;\
    if (x == 0)\
        i = 0;\
    else {\
        unsigned long y = \
        ((unsigned long)sizeof(unsigned long)) \
            * __CHAR_BIT__ - 1 - __builtin_clz(x); \
        i = (int)((y << 1) + ((s >> (y + (BIGBIN_SHIFT - 1)))));\
        i += BIN_SMALL_THRESHOLD; \
    }\
}

#define TAG_SIZE (sizeof(unsigned long) << 1)

#define node_size(x) \
    ((x) & ~(1UL << ((sizeof(unsigned long) << CHAR_BIT_SHIFT) - 1)))
#define node_isused(x) \
    ((x) & (1UL << ((sizeof(unsigned long) << CHAR_BIT_SHIFT) - 1)))
#define node_used(x) \
    ((x) |= (1UL << ((sizeof(unsigned long) << CHAR_BIT_SHIFT) - 1)))
#define node_unused(x) \
    ((x) &= ~(1UL << ((sizeof(unsigned long) << CHAR_BIT_SHIFT) - 1)))
#define off_to_addr(x, y) ((x)->mem_block + (y))
#define off_to_node(p, off) \
    (off ? (struct mem_node *)(p + off) : 0)
#define ptr_to_off(p, n) ((void *)n - (void *)p)

#define node_to_tail(p, s) \
    (((void *)p) + s - sizeof(unsigned long))
#define node_tail_size(p, s) \
    (*(unsigned long *)node_to_tail(p, s))
#define node_head_size(p) (*(unsigned long *)p)
#define node_prev_size(p) \
    (*(unsigned long *)((void *)p - sizeof(unsigned long)))

#define node_to_next(p, s) (((void *)p) + s)
#define node_to_prev(p, n) \
    ((void *)n <= (void *)p + LOW_SIZE ? \
     0 : ((void *)n) - node_prev_size(n))

#define node_list_next(p, node) \
    (node->next ? \
     (struct mem_node *)(p + node->next) : 0)
#define node_list_prev(p, node) \
    (node->prev ? \
     (struct mem_node *)(p + node->prev) : 0)

#define number_align(x, y) (((x) + (y) - 1) & ~((y) - 1))
#define align_8(x) number_align(x, 8)

struct mem_node {
    unsigned long use_a_size;
    unsigned long prev;
    unsigned long next;
};

struct mem_info {
    void *mem_block;
    unsigned long block_size;
    //futex_t *futex;
    mem_lock_t *lock;
    //long error;
    int shmid;
    unsigned long *mem_bin;
};

inline static unsigned long size_2_index(unsigned long);

inline static void __node_init(
        struct mem_node *, unsigned long);

inline static int __node_insert(
        struct mem_info *, unsigned long);

inline static unsigned long __node_merge(
        struct mem_info *, unsigned long);

inline static unsigned long __node_merge_core(
        struct mem_info *, unsigned long);

inline static unsigned long __node_merge_next(
        struct mem_info *, unsigned long);

inline static int __node_can_merge_next(
        struct mem_info *, unsigned long);

inline static unsigned long __node_merge_prev(
        struct mem_info *, unsigned long);

inline static unsigned long __node_can_merge_prev(
        struct mem_info *, unsigned long);


inline static unsigned long __node_remove(
        struct mem_info *, unsigned long);


inline static unsigned long __node_split(
        struct mem_info *,
        unsigned long,
        unsigned long);

inline static unsigned long __node_find(
        struct mem_info *, unsigned long);

static struct mem_node *__node_find_min(
        void *, unsigned long *, unsigned long);

#ifdef SMALL_SIZE_BOOST
static void __node_merge_all(struct mem_info *, int, int);

static struct mem_node *__node_find_low(
        void *, unsigned long *, unsigned long, unsigned long);

static struct mem_node *__node_find_high(
        void *, unsigned long *, unsigned long, unsigned long);
#endif


inline static unsigned long size_2_index(unsigned long s)
{
    int idx;
    if(s <= SIZE_SMALL_THRESHOLD)
        idx = SMALL_SIZE_2_INDEX(s);
    else
        BIG_SIZE_2_INDEX(s, idx);
    return idx;
}

static void __node_init(struct mem_node *p, unsigned long s)
{
    p->use_a_size = s;
    p->next = p->prev = 0;
    node_tail_size(p, s) = s;
}

inline static int __node_insert(
        struct mem_info *info, unsigned long off)
{
    struct mem_node *p = info->mem_block + off;
    p->next = p->prev = 0;

    unsigned long s = node_size(p->use_a_size);
    int idx = size_2_index(s);

    p->next = info->mem_bin[idx];
    info->mem_bin[idx] = off;
    if(p->next) {
        struct mem_node *next =
            (struct mem_node *)
            off_to_addr(info, p->next);
        next->prev = off;
    }
    return 0;
}

inline static unsigned long __node_merge(
        struct mem_info *info, unsigned long off)
{
    off =  __node_merge_core(info, off);
    assert(off);

    /*void *p = info->mem_block;
    struct mem_node *node =
        (struct mem_node *)(p + off);
    node->prev = node->next = 0;*/

    return off;
}

inline static unsigned long __node_merge_core(
        struct mem_info *info, unsigned long off)
{
    off = __node_merge_next(info, off);
    off = __node_merge_prev(info, off);
    return off;
}

inline static unsigned long __node_can_merge_prev(
        struct mem_info *info, unsigned long off)
{
    if(off >= LOW_SIZE) {
        void *p = info->mem_block;
        struct mem_node *node =
            (struct mem_node *)(p + off);
        //unsigned long cs = node_size(node->use_a_size);
        struct mem_node *prev = node_to_prev(p, node);
        void *high = p + LOW_SIZE;
        if((void *)prev < high)
            return 0;
        return !node_isused(prev->use_a_size);
    }
    return 0;
}

inline static unsigned long __node_merge_prev(
        struct mem_info *info, unsigned long off)
{
    if(off >= LOW_SIZE) {
        void *p = info->mem_block;
        struct mem_node *node =
            (struct mem_node *)(p + off);
        unsigned long cs = node_size(node->use_a_size);
        struct mem_node *prev = node_to_prev(p, node);
        void *high = p + LOW_SIZE;
        if((void *)prev < high)
            return off;
        if(!node_isused(prev->use_a_size)) {
            unsigned long ps =
                node_size(prev->use_a_size);
            assert(ps);
            __node_remove(info, off - ps);
            unsigned long sum = cs + ps;
            node_tail_size(prev, sum) = sum;
            prev->use_a_size = sum;
            return __node_merge_prev(info, off - ps);
        }
        return off;
    }
    assert(0);
    return 0;
}

#ifdef SMALL_SIZE_BOOST
static void __node_merge_all(struct mem_info *info, int b, int e)
{
    unsigned long *bin = info->mem_bin;
    void *p = info->mem_block;
    for(int i = b; i < e; ++i) {
        for(struct mem_node *n =
                off_to_node(p, bin[i]); n;) {
            unsigned long off = ptr_to_off(p, n);

            if(__node_can_merge_prev(info, off) ||
                    __node_can_merge_next(info, off)) {
                __node_remove(info, off);

                off = __node_merge(info, off);
                __node_insert(info, off);

                n = off_to_node(p, bin[i]);
            } else {
                n = node_list_next(p, n);
            }
        }
    }
}
#endif

inline static int __node_can_merge_next(
        struct mem_info *info, unsigned long off)
{
    if(off < info->block_size) {
        void *p = info->mem_block;
        struct mem_node *node =
            (struct mem_node *)(p + off);
        unsigned long cs = node_size(node->use_a_size);
        unsigned long hs = info->block_size;
        if(off + cs >= hs)
            return 0;
        struct mem_node *next =
            (struct mem_node *)node_to_next(
                node, cs);
        return !node_isused(next->use_a_size);
    }
    return 0;
}

inline static unsigned long __node_merge_next(
        struct mem_info *info, unsigned long off)
{
    if(off < info->block_size) {
        void *p = info->mem_block;
        struct mem_node *node =
            (struct mem_node *)(p + off);
        unsigned long cs = node_size(node->use_a_size);
        unsigned long hs = info->block_size;
        if(off + cs >= hs)
            return off;
        struct mem_node *next =
            (struct mem_node *)node_to_next(
                node, cs);
        if(!node_isused(next->use_a_size)) {
            __node_remove(info, off + cs);
            unsigned long ns = node_size(
                next->use_a_size);
            assert(ns);
            unsigned long sum = cs + ns;
            node->use_a_size = sum;
            node_tail_size(node, sum) = sum;
            return __node_merge_next(
                info, off);
        }
        return off;
    }
    assert(0);
    return 0;
}

inline static unsigned long __node_remove(
        struct mem_info *info, unsigned long off)
{
    void *p = info->mem_block;
    struct mem_node *node =
        (struct mem_node *)(p + off);

    if(node->prev) {
        struct mem_node *prev =
            (struct mem_node *)(p + node->prev);
        prev->next = node->next;
    } else {
        unsigned long s = node_size(node->use_a_size);
        int idx = size_2_index(s);
        unsigned long *bin = info->mem_bin;
        bin[idx] = node->next;
    }
    if(node->next) {
        struct mem_node *next =
            (struct mem_node *)(p + node->next);
        next->prev = node->prev;
    }
    node->prev = node->next = 0;
    return off;
}

inline static unsigned long __node_split(
        struct mem_info *info,
        unsigned long off,
        unsigned long s)
{
    void *p = info->mem_block;
    struct mem_node *node =
        (struct mem_node *)(p + off);

    unsigned long ns = node_size(node->use_a_size);
    if(s + SMALLEST_SIZE >= ns)
        return off;

    node->use_a_size = s;
    node_tail_size(node, s) = s;
    struct mem_node *next =
        (struct mem_node *)node_to_next(node, s);
    ns -= s;
    next->use_a_size = ns;
    node_tail_size(next, ns) = ns;

    __node_insert(info, off + s);
    return off;
}

static struct mem_node *__node_find_min(
        void *p, unsigned long *bin, unsigned long s)
{
#ifdef SMALL_SIZE_BOOST
    int idx = size_2_index(s);
    struct mem_node *node = 0;
    if(idx <= BIN_SMALL_THRESHOLD)
        node =  __node_find_low(p, bin, idx, s);
    return (node ? node : __node_find_high(p, bin, idx, s));
#else
    int idx = size_2_index(s);
    struct mem_node *node, *nmin = 0;
    unsigned long min, tmp;
    for(unsigned i = idx; i < BIN_NUMBER; ++i) {
        node = off_to_node(p, bin[i]);
        if(node) min = node_size(node->use_a_size) + 1;
        for(; node; node = node_list_next(p, node)) {
            tmp = node_size(node->use_a_size);
            if(tmp >= s && tmp < min) {
                nmin = node;
                min = tmp;
            }
        }
        if(nmin)
            return nmin;
    }
    return 0;
#endif
}

#ifdef SMALL_SIZE_BOOST
static struct mem_node *__node_find_high(
        void *p, unsigned long *bin, unsigned long idx, unsigned long s)
{
    //int idx = size_2_index(s);
    struct mem_node *node, *nmin = 0;
    unsigned long min, tmp;
    for(unsigned i = idx; i < BIN_NUMBER; ++i) {
        node = off_to_node(p, bin[i]);
        if(node) min = node_size(node->use_a_size) + 1;
        for(; node; node = node_list_next(p, node)) {
            tmp = node_size(node->use_a_size);
            if(tmp >= s && tmp < min) {
                nmin = node;
                min = tmp;
            }
        }
        if(nmin)
            return nmin;
    }
    return 0;
}

static struct mem_node *__node_find_low(
        void *p, unsigned long *bin, unsigned long idx, unsigned long s)
{
    //int idx = size_2_index(s);
    struct mem_node *node;
    for(unsigned long i = idx; i <= BIN_SMALL_THRESHOLD; ++i) {
        for(node = off_to_node(p, bin[i]); node;
                node = node_list_next(p, node)) {
            if(node_size(node->use_a_size) >= s)
                return node;
        }
    }
    return 0;
}
#endif

// XXX hot spot
inline static unsigned long __node_find(
        struct mem_info *info, unsigned long s)
{
    unsigned long *bin = info->mem_bin;
    void *p = info->mem_block;
    struct mem_node *node;

#ifdef SMALL_SIZE_BOOST
    int m = 2;
    while(m){
#endif
        if((node =  __node_find_min(p, bin, s))) {
            unsigned long ret = (void *)node - p;
            unsigned long ns = node_size(node->use_a_size);
            __node_remove(info, ret);
            if(ns > s)
                ret = __node_split(info, ret, s);
            return ret;
        }
        //break;
#ifdef SMALL_SIZE_BOOST
        if(--m) __node_merge_all(info, 0, (int)BIN_NUMBER);
        //printf("%s: %s: %d\n", __FILE__, __PRETTY_FUNCTION__, __LINE__);
    }
#endif
    return 0;
}

unsigned long mem_alloc(struct mem_info *info, unsigned long s)
{
    if(!s) return 0;
    if((s = align_8(s + TAG_SIZE)) < SMALLEST_SIZE)
        s = SMALLEST_SIZE;

    unsigned long off;

    //futex_lock(info->futex);
    mem_lock_lock(info->lock);
    if(!(off = __node_find(info, s))) {
        //futex_unlock(info->futex);
        mem_lock_unlock(info->lock);
        return 0;
    }
    struct mem_node *node =
        off_to_node(info->mem_block, off);
    node_used(node->use_a_size);
    //futex_unlock(info->futex);
    mem_lock_unlock(info->lock);

    return off + sizeof(unsigned long);
}

void mem_free(struct mem_info *info, unsigned long off)
{
    off -= sizeof(unsigned long);
    assert(off >= LOW_SIZE);
    assert(off < info->block_size);

    struct mem_node *node =
        off_to_node(info->mem_block, off);

    //futex_lock(info->futex);
    mem_lock_lock(info->lock);
    node_unused(node->use_a_size);
    //node->prev = node->next = 0;

#ifndef SMALL_SIZE_BOOST
    off = __node_merge(info, off);
#endif
    __node_insert(info, off);

#ifdef SMALL_SIZE_BOOST
    static int count = 0;
    if(++count == 70) {
        count = 0;
        //printf("%s: %s: %d\n", __FILE__, __PRETTY_FUNCTION__, __LINE__);
        __node_merge_all(info, BIN_SMALL_THRESHOLD, (int)BIN_NUMBER);
    }
#endif
    //futex_unlock(info->futex);
    mem_lock_unlock(info->lock);
}

struct mem_info *mem_init(void *p, unsigned long s, int b)
{
    if(s < LOW_SIZE + SMALLEST_SIZE)
        return 0;

    struct mem_info *info =
        (struct mem_info *)
        malloc(sizeof(struct mem_info));
    //info->futex = (futex_t *)p;
    info->lock = (mem_lock_t *)p;
    //info->mem_bin = (unsigned long *)(p + sizeof(futex_t));
    info->mem_bin = (unsigned long *)(p + sizeof(mem_lock_t));
    info->mem_block = p;
    info->block_size = s;
    //info->error = 0;
    info->shmid = -1;
    //futex_create();
    if(b) {
        //futex_init(info->lock);
        mem_lock_init(info->lock);
        //futex_lock(info->futex);
        mem_lock_lock(info->lock);
        memset(info->mem_bin, 0, BIN_SIZE);
        struct mem_node *node =
            (struct mem_node *)(p + LOW_SIZE);

        __node_init(node, info->block_size - LOW_SIZE);
        __node_insert(info, LOW_SIZE);
        //futex_unlock(info->futex);
        mem_lock_unlock(info->lock);
    }
    return info;
}

void mem_destroy(struct mem_info *info)
{
    //futex_lock(info->futex);
    mem_lock_lock(info->lock);
    if(info->shmid >= 0)
        shmctl(info->shmid, IPC_RMID, 0);
    free(info);
    //futex_unlock(info->futex);
    mem_lock_unlock(info->lock);
}

struct mem_info *mem_link_shm(key_t key, size_t s, int init)
{
    int mid;
    s += LOW_SIZE + SMALLEST_SIZE;
    s = align_8(s);
    if((mid = shmget(key, s, IPC_CREAT | 0666)) < 0) {
        perror("shmget");
        return 0;
    }
    void *p;
    if((p = shmat(mid, 0, 0)) == (void *)-1) {
        perror("shmat");
        return 0;
    }
    struct mem_info *info =
        mem_init(p, (unsigned long)s, init);
    assert(info);
    info->shmid = mid;
    return info;
}

int mem_detach_shm(struct mem_info *info)
{
    if(shmdt(info->mem_block)) {
        perror("shmdt");
        return -1;
    }
    return 0;
}

void *mem_off_2_ptr(struct mem_info *info, unsigned long off)
{
    if(off >= LOW_SIZE)
        return info->mem_block + off;
    return 0;
}

unsigned long mem_ptr_2_off(struct mem_info *info, void *p)
{
    unsigned long off;
    if((off = p - info->mem_block) >= LOW_SIZE)
        return off;
    return 0;
}
===========================================================

mem_lock.h:
===========================================================
// 2011年 09月 13日 星期二 10:43:03 CST
// author: 李小丹(Li Shao Dan) 字 殊恒(shuheng)
// K.I.S.S
// S.P.O.T

#ifndef MEM_LOCK_H
#define MEM_LOCK_H

#include <unistd.h>
#include <sched.h>
#include <sys/syscall.h>

typedef struct __mem_lock {
    unsigned long tid;
    unsigned long lock;
} mem_lock_t;

inline static int mem_lock_init(mem_lock_t *);
inline static int mem_lock_lock(mem_lock_t *);
inline static int mem_lock_unlock(mem_lock_t *);

inline static int mem_lock_init(mem_lock_t *lk)
{
    lk->tid = 0;
    lk->lock = 0;
    return 0;
}

#define SPIN_YIELD_INTERVAL 31U

inline static int mem_lock_lock(mem_lock_t *lk)
{
    pid_t now = syscall(SYS_gettid);

    pid_t old =
        (pid_t)__sync_and_and_fetch(&lk->tid, ~0UL);

    //if(__sync_bool_compare_and_swap(
    //        &lk->tid, now, now))
    if(old == now)
        return 1;

    int c = 0;
    while(__sync_lock_test_and_set(
            &lk->lock, 1)) {
        if(!(++c & SPIN_YIELD_INTERVAL))
            sched_yield();
    }
    lk->tid = (unsigned long)now;
    return 0;
}

inline static int mem_lock_unlock(mem_lock_t *lk)
{
    unsigned long now =
        (unsigned long)syscall(SYS_gettid);
    unsigned long old =
        __sync_and_and_fetch(&lk->tid, ~0UL);

    //if(!__sync_bool_compare_and_swap(
        //    &lk->tid, now, now))
    if(old != now)
        return -1;
    lk->tid = 0;
    __sync_lock_release(&lk->lock);
    return 0;
}

#endif
===========================================================

main.c:
===========================================================
// 2011年 08月 26日 星期五 10:17:33 CST
// author: 李小丹(Li Shao Dan) 字 殊恒(shuheng)
// K.I.S.S
// S.P.O.T

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <time.h>
#include <signal.h>
#include <string.h>

#include <unistd.h>
#include <pthread.h>

#include "mem_alloc.h"
#include "mem_lock.h"

//#ifndef SINGLE_PROCESS
#define BUF_SIZE (0x1FFFFFUL << 1)
//#else
//#define BUF_SIZE 0xFFFFFUL
//#endif

struct mem_info *info;

static void sig_handle(int);

void *do_work(void *);


int main(int argc, char *argv[])
{
    if(argc != 2)
        exit(1);

    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = sig_handle;
    sigemptyset(&sa.sa_mask);
    if(sigaction(SIGINT, &sa, 0) < 0) {
        perror("sigaction");
        exit(1);
    }

    srand(time(0));

    unsigned long as = BUF_SIZE;
    //void *p = malloc(as);

    key_t key = ftok("./main.c", 0);
    info = mem_link_shm(key, as, atoi(argv[1]));
#ifndef SINGLE_PROCESS
    pthread_t tid;
    pthread_create(&tid, 0, do_work, (void *)0);
#endif

    //info = mem_init(p, as, 1);
    assert(info);

    unsigned long p1, p2, p3, p4;
    unsigned long s1, s2, s3;
    p1 = mem_alloc(info, 524288);
    assert(p1);
    char *ptr4[4];
    // not free
    unsigned long h1 = mem_alloc(info, 12);
    ptr4[0] = mem_off_2_ptr(info, h1);
    strcpy(ptr4[0], "hello,world");
    ////////////////////////////////////
    p2 = mem_alloc(info, 8192);
    assert(p2);
    // not free
    unsigned long h2 = mem_alloc(info, 12);
    ptr4[1] = mem_off_2_ptr(info, h2);
    strcpy(ptr4[1], "hello,world");
    //////////////////////////////////////////
    p3 = mem_alloc(info, 32768);
    assert(p3);
    // not free
    unsigned long h3 = mem_alloc(info, 12);
    ptr4[2] = mem_off_2_ptr(info, h3);
    strcpy(ptr4[2], "hello,world");
    /////////////////////////////////////

    p4 = mem_alloc(info, 65535);
    assert(p4);
    // not free
    unsigned long h4 = mem_alloc(info, 12);
    ptr4[3] = mem_off_2_ptr(info, h4);
    strcpy(ptr4[3], "hello,world");
    ///////////////////////////////////////


    void *ppp = mem_off_2_ptr(info, p1);
    unsigned long pp1 = mem_ptr_2_off(info, ppp);
    assert(pp1 == p1);

    mem_free(info, p1);
    mem_free(info, p2);
    mem_free(info, p3);
    mem_free(info, p4);

    int count = 0;

    time_t cur, last = time(0);
    for(;;) {
        while(!(s1 = rand() % 524288)) ;
        while(!(s2 = rand() % 8192)) ;
        p1 = mem_alloc(info, s1);
        p2 = mem_alloc(info, s2);
        assert(p1);
        assert(p2);
        if(s1 > 16) {
            char *ppp = mem_off_2_ptr(info, p1);
            strcpy(ppp, "hello,world");
            //printf("%s\n", ppp);
        }
//        printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s1, p1);
//        printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s2, p2);
        mem_free(info, p2);
        mem_free(info, p1);

        while(!(s1 = rand() % 32)) ;
        while(!(s2 = rand() % 65535)) ;
        p1 = mem_alloc(info, s1);
        p2 = mem_alloc(info, s2);
        assert(p1);
        assert(p2);
//        printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s1, p1);
//        printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s2, p2);

        mem_free(info, p2);

        while(!(s3 = rand() % 4096)) ;
        p3 = mem_alloc(info, s3);
        assert(p3);

        unsigned long pp[100];
        for(int i = 0; i < 100; ++i) {
            while(!(s3 = rand() % 4096)) ;
            //while(!(s3 = rand() % 409)) ;
            pp[i] = mem_alloc(info, s3);
            assert(pp[i]);
            /*if(s3 > 16) {
                char *ppp = mem_off_2_ptr(info, pp[i]);
                strcpy(ppp, "hello,world");
                //printf("%s\n", ppp);
            }*/
            //            printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s3, pp[i]);
        }

//        printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s3, p3);
        mem_free(info, p3);
        mem_free(info, p1);

        //while(!(s1 = rand() % 524288)) ;
        while(!(s1 = rand() % 124288)) ;
        while(!(s2 = rand() % 64)) ;
        while(!(s3 = rand() % 32768)) ;
        p1 = mem_alloc(info, s1);
        p2 = mem_alloc(info, s2);
        p3 = mem_alloc(info, s3);
        assert(p1);
        assert(p2);
        assert(p3);
//        printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s1, p1);
//        printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s2, p2);
//        printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s3, p3);
        mem_free(info, p2);
        mem_free(info, p3);

        for(int i = 99; i >= 0; --i)
            mem_free(info, pp[i]);

        mem_free(info, p1);
        //static int aaaaaaa = 0;
        if(++count == 100000) {
            cur = time(0);
            printf("XXX: %lu\n", cur - last);
            for(int i = 0; i < 4; ++i)
                printf("%s\n", ptr4[i]);
            count = 0;
            last = cur;
            /*if(++aaaaaaa == 3)
                exit(0);*/
        }
    }
    return 0;
}

static void sig_handle(int s)
{

    printf("\ntid is %ld\n", syscall(SYS_gettid));
    psignal(s, "\ndestroy shared memory");
    mem_destroy(info);
    exit(0);
}

void *do_work(void *p)
{
    int mi = (int)p;

    unsigned long as = BUF_SIZE;
    //void *p = malloc(as);

    key_t key = ftok("./main.c", 0);
    info = mem_link_shm(key, as, mi);

    //info = mem_init(p, as, 1);
    assert(info);

    unsigned long p1, p2, p3, p4;
    unsigned long s1, s2, s3;
    p1 = mem_alloc(info, 524288);
    assert(p1);
    char *ptr4[4];
    // not free
    unsigned long h1 = mem_alloc(info, 12);
    ptr4[0] = mem_off_2_ptr(info, h1);
    strcpy(ptr4[0], "hello,world");
    ////////////////////////////////////
    p2 = mem_alloc(info, 8192);
    assert(p2);
    // not free
    unsigned long h2 = mem_alloc(info, 12);
    ptr4[1] = mem_off_2_ptr(info, h2);
    strcpy(ptr4[1], "hello,world");
    //////////////////////////////////////////
    p3 = mem_alloc(info, 32768);
    assert(p3);
    // not free
    unsigned long h3 = mem_alloc(info, 12);
    ptr4[2] = mem_off_2_ptr(info, h3);
    strcpy(ptr4[2], "hello,world");
    /////////////////////////////////////

    p4 = mem_alloc(info, 65535);
    assert(p4);
    // not free
    unsigned long h4 = mem_alloc(info, 12);
    ptr4[3] = mem_off_2_ptr(info, h4);
    strcpy(ptr4[3], "hello,world");
    ///////////////////////////////////////


    void *ppp = mem_off_2_ptr(info, p1);
    unsigned long pp1 = mem_ptr_2_off(info, ppp);
    assert(pp1 == p1);

    mem_free(info, p1);
    mem_free(info, p2);
    mem_free(info, p3);
    mem_free(info, p4);

    int count = 0;

    time_t cur, last = time(0);
    for(;;) {
        while(!(s1 = rand() % 524288)) ;
        while(!(s2 = rand() % 8192)) ;
        p1 = mem_alloc(info, s1);
        p2 = mem_alloc(info, s2);
        assert(p1);
        assert(p2);
        if(s1 > 16) {
            char *ppp = mem_off_2_ptr(info, p1);
            strcpy(ppp, "hello,world");
            //printf("%s\n", ppp);
        }
//        printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s1, p1);
//        printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s2, p2);
        mem_free(info, p2);
        mem_free(info, p1);

        while(!(s1 = rand() % 32)) ;
        while(!(s2 = rand() % 65535)) ;
        p1 = mem_alloc(info, s1);
        p2 = mem_alloc(info, s2);
        assert(p1);
        assert(p2);
//        printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s1, p1);
//        printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s2, p2);

        mem_free(info, p2);

        while(!(s3 = rand() % 4096)) ;
        p3 = mem_alloc(info, s3);
        assert(p3);

        unsigned long pp[100];
        for(int i = 0; i < 100; ++i) {
            while(!(s3 = rand() % 4096)) ;
            //while(!(s3 = rand() % 409)) ;
            pp[i] = mem_alloc(info, s3);
            assert(pp[i]);
            if(s3 > 16) {
                char *ppp = mem_off_2_ptr(info, pp[i]);
                strcpy(ppp, "hello,world");
                //printf("%s\n", ppp);
            }
            //            printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s3, pp[i]);
        }

//        printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s3, p3);
        mem_free(info, p3);
        mem_free(info, p1);

        //while(!(s1 = rand() % 524288)) ;
        while(!(s1 = rand() % 124288)) ;
        while(!(s2 = rand() % 64)) ;
        while(!(s3 = rand() % 32768)) ;
        p1 = mem_alloc(info, s1);
        p2 = mem_alloc(info, s2);
        p3 = mem_alloc(info, s3);
        assert(p1);
        assert(p2);
        assert(p3);
//        printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s1, p1);
//        printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s2, p2);
//        printf("%d XXX: size: %lu, offset: %lu\n", __LINE__, s3, p3);
        mem_free(info, p2);
        mem_free(info, p3);

        for(int i = 99; i >= 0; --i)
            mem_free(info, pp[i]);

        mem_free(info, p1);
        //static int aaaaaaa = 0;
        if(++count == 100000) {
            cur = time(0);
            printf("XXX: %lu\n", cur - last);
            for(int i = 0; i < 4; ++i)
                printf("%s\n", ptr4[i]);
            count = 0;
            last = cur;
            /*if(++aaaaaaa == 3)
                exit(0);*/
        }
    }
    return (void *)0;
}
===========================================================

makefile:
===========================================================
mod=SMALL_SIZE_BOOST
proc=SINGLE_PROCESS
mytest: main.c mem_alloc.c mem_alloc.h mem_lock.h
    gcc -std=c99 -O2 -g -W -Wall -Wextra -D_GNU_SOURCE -D$(mod) -o $@ main.c mem_alloc.c -lpthread

.PHONY:clean
clean:
    -rm -rf mytest
===========================================================