Chinaunix首页 | 论坛 | 博客
  • 博客访问: 779363
  • 博文数量: 265
  • 博客积分: 6010
  • 博客等级: 准将
  • 技术积分: 1985
  • 用 户 组: 普通用户
  • 注册时间: 2009-07-13 12:33
文章分类

全部博文(265)

文章存档

2011年(1)

2010年(66)

2009年(198)

我的朋友

分类: LINUX

2010-09-07 20:47:03

本文的 Share Memory 又可称为 Memory Pool,就是在匿名内存映射区(mmap) 预先划出一大块内存,以后的分配操作都可以在这块内存内部进行,包括 malloc、calloc、free 等等。Memory Pool 的好处是不在堆(Heap)和栈(CallStack)上分配,可以重复使用,避免多次向内核请求分配和释放内存,一定程度上提高了性能。另外只需释放整个 Pool 即可完成所有的内存释放,避免内存泄露的发生。

安装 libmm 库:
$ sudo apt-get libmm14 libmm-dev libmm-dbg

头文件: /usr/include/mm.h
/* Standard Malloc-Style API */
MM     *mm_create(size_t, const char *);
int     mm_permission(MM *, mode_t, uid_t, gid_t);
void    mm_reset(MM *);
void    mm_destroy(MM *);
int     mm_lock(MM *, mm_lock_mode);
int     mm_unlock(MM *);
void   *mm_malloc(MM *, size_t);
void   *mm_realloc(MM *, void *, size_t);
void    mm_free(MM *, void *);
void   *mm_calloc(MM *, size_t, size_t);
char   *mm_strdup(MM *, const char *);
size_t  mm_sizeof(MM *, const void *);
size_t  mm_maxsize(void);
size_t  mm_available(MM *);
char   *mm_error(void);
void    mm_display_info(MM *);

和标准库内存分配函数差不多,很好理解。
#include 
#include 
#include 
#include 
#include 

int main(int argc, char* argv[])
{
    // 创建 10KB 内存池 (最小 8192),"abc" 是创建锁定标识文件名。
    MM* pool = mm_create(1024 * 10, "abc");

    // 锁定池,在当前目录下创建 abc.sem 文件。
    mm_lock(pool, MM_LOCK_RW);

    // 在池内分配内存块。
    int* x = mm_malloc(pool, sizeof(int));
    *x = 1234;

    // 获取池内分配的某个块大小。
    printf("%p = %d\n", x, mm_sizeof(pool, x));

    // 显式整个池状态信息。
    mm_display_info(pool);
    printf("max:%d, avail:%d\n", mm_maxsize(), mm_available(pool));

    getchar();

    // 删除 abc.sem,解除锁定。
    mm_unlock(pool);

    // 释放整个池。
    mm_destroy(pool);

    return EXIT_SUCCESS;
}

输出:
$ gcc -g -o test -lmm main.c

$ ldd ./test
    linux-gate.so.1 =>  (0xb7729000)
    libmm.so.14 => /usr/lib/libmm.so.14 (0xb771c000)
    libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb75d7000)
    /lib/ld-linux.so.2 (0xb772a000)

$ ./test
0xb7850034 = 4
Information for MM
    memory area     = 0xb7850014 - 0xb78a0314
    memory size     = 10264
    memory offset   = 40
    bytes spare     = 10224
    bytes free      = 0 (0 chunks)
    bytes allocated = 16
    List of free chunks:
        
max:33546216, avail:10224

对照输出的地址信息,我们可以看 ./test 进程的内存映射数据。
$ ps aux | grep test
yuhen     2406  0.0  0.0   1576   440 pts/1    S+   19:37   0:00 ./test

$ cat /proc/2406/maps

08048000-08049000 r-xp 00000000 fc:00 30456      /home/yuhen/projects/c/test
08049000-0804a000 r--p 00000000 fc:00 30456      /home/yuhen/projects/c/test
0804a000-0804b000 rw-p 00001000 fc:00 30456      /home/yuhen/projects/c/test
b7701000-b7703000 rw-p 00000000 00:00 0
b7703000-b7841000 r-xp 00000000 fc:00 690        /lib/tls/i686/cmov/libc-2.10.1.so
b7841000-b7842000 ---p 0013e000 fc:00 690        /lib/tls/i686/cmov/libc-2.10.1.so
b7842000-b7844000 r--p 0013e000 fc:00 690        /lib/tls/i686/cmov/libc-2.10.1.so
b7844000-b7845000 rw-p 00140000 fc:00 690        /lib/tls/i686/cmov/libc-2.10.1.so
b7845000-b7848000 rw-p 00000000 00:00 0
b7848000-b784b000 r-xp 00000000 fc:00 50664      /usr/lib/libmm.so.14.0.22
b784b000-b784d000 rw-p 00003000 fc:00 50664      /usr/lib/libmm.so.14.0.22
b784d000-b784f000 rw-p 00000000 00:00 0
b784f000-b7853000 rw-s 00000000 00:09 491521     /SYSV00000000 (deleted)
b7853000-b7855000 rw-p 00000000 00:00 0
b7855000-b7856000 r-xp 00000000 00:00 0          [vdso]
b7856000-b7871000 r-xp 00000000 fc:00 599        /lib/ld-2.10.1.so
b7871000-b7872000 r--p 0001a000 fc:00 599        /lib/ld-2.10.1.so
b7872000-b7873000 rw-p 0001b000 fc:00 599        /lib/ld-2.10.1.so
bfd3c000-bfd51000 rw-p 00000000 00:00 0          [stack]

再试试其他的函数。
#include 
#include 
#include 
#include 
#include 

int main(int argc, char* argv[])
{
    MM* pool = mm_create(1024 * 10, "abc");

    /* --------- DUP ------------------ */
    char* s1 = mm_malloc(pool, 10);
    strcpy(s1, "abcd");

    char* s2 = mm_strdup(pool, s1);
    printf("s1=%p,%s, s2=%p,%s\n", s1, s1, s2, s2);

    printf("[Befor Reset] available: %d\n", mm_available(pool));

    /* --------- RESET ----------------- */
    mm_reset(pool);
    printf("[After Reset] available: %d\n", mm_available(pool));

    int* x = mm_malloc(pool, sizeof(int));
    *x = 0x1234;
    printf("x=%p,0x%x\n", x, *x);

    /* --------- ERROR ----------------- */
    char* s = mm_malloc(pool, 1024 * 20);
    if (!s) printf("%s\n",  mm_error());

    /* --------- INFO ------------------ */
    mm_display_info(pool);

    mm_destroy(pool);

    return EXIT_SUCCESS;
}

输出:
c$ ./test

s1=0xb78d8034,abcd, s2=0xb78d804c,abcd

[Befor Reset] available: 10200

[After Reset] available: 10240
x=0xb78d8034,0x1234

mm:alloc: out of memory

Information for MM
    memory area     = 0xb78d8014 - 0xb7928314
    memory size     = 10264
    memory offset   = 40
    bytes spare     = 10224
    bytes free      = 0 (0 chunks)
    bytes allocated = 16
    List of free chunks:
        

调用 mm_reset() 后内存池重新 "从头" 分配,当超出最大尺寸时返回 NULL。这些操作不会导致内存泄露。尽管池创建时都被初始化为 0,但随着分配和释放,池和堆一样会遗留大量垃圾数据,因此注意使用 mm_malloc() 和 mm_calloc()。
$ valgrind --leak-check=full ./test
==2654== Memcheck, a memory error detector
==2654== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==2654== Using Valgrind-3.5.0-Debian and LibVEX; rerun with -h for copyright info
==2654== Command: ./test
==2654==
==2654==
==2654== HEAP SUMMARY:
==2654==    in use at exit: 0 bytes in 0 blocks
==2654==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==2654==
==2654== All heap blocks were freed -- no leaks are possible
==2654==
==2654== For counts of detected and suppressed errors, rerun with: -v
==2654== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 15 from 8)

mm.h 还有一组以大写字母 MM 开头的函数,不过是用了一个全局变量存储池指针,然后内部调用 mm_xxx() 而已。
000016c0 :
    16c0:       55                      push   ebp
    16c1:       89 e5                   mov    ebp,esp
    16c3:       53                      push   ebx
    16c4:       e8 4e fd ff ff          call   1417 
    16c9:       81 c3 2b 29 00 00       add    ebx,0x292b
    16cf:       83 ec 04                sub    esp,0x4
    16d2:       8b 83 34 01 00 00       mov    eax,DWORD PTR [ebx+0x134]
    16d8:       85 c0                   test   eax,eax
    16da:       74 08                   je     16e4 
    16dc:       89 04 24                mov    DWORD PTR [esp],eax
    16df:       e8 d8 fa ff ff          call   11bc 
    16e4:       83 c4 04                add    esp,0x4
    16e7:       5b                      pop    ebx
    16e8:       5d                      pop    ebp
    16e9:       c3                      ret
    16ea:       8d b6 00 00 00 00       lea    esi,[esi+0x0]
阅读(3557) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~