C语言自动管理动态分配内存的一种方法
正常情况下用malloc分配内存,用free释放内存,用realloc重新分配,分配的内存必须要释放,我们的思路是自定义一个函数my_alloc,用户调用my_alloc函数分配的内存都自动记录在一个指针数组mempool中,这个数组在程序运行时首先初始化,每次调用my_alloc函数,都将分配的内存指针记录在mempool中,在程序运行结束前将mempool中记录的内存指针依次释放,最后将mempool释放,如此操作,用户只需调用my_alloc分配内存就可以了,不必顾及其他问题。
自定义静态变量和相关函数,测试一下分配1000次内存
- #define PAGESIZE 128 定义宏PAGESIZE每次为mempool增加128个指针
- static void **mempool = NULL; 无类型指针数组,保存分配的内存指针
- static int pcount = 0; 记录分配内存的次数,每次加一
- static int ps = 1; 记录mempool重新分配内存的次数
- xmalloc函数,调用malloc分配内存,如出错则显示信息并返回NULL!!!
- my_mempool_init函数,初始化mempool,为无类型指针数组分配128个指针!
- my_alloc函数,分配内存,保存内存指针,记录次数,等于ps*PAGESIZE则ps增一,重新为mempool分配内存!!!
- my_mempool_free函数,释放所有分配的内存
- my_mempool_out_info函数,输出mempool相关的信息
- my_strlen函数,自定义求字符串长度的函数
- my_strdup函数,自定义字符串复制函数,返回复制的字符串的指针,这个指针是用myalloc在内存中分配的,只需要在程序运行结束前用my_mempool_free统一释放就可以了。
代码如下:
/* filename: mem.c */
#include <stdio.h>
#include <stdlib.h>
/**/
#define PAGESIZE 128
/**/
static void **mempool = NULL;
static int pcount = 0;
static int ps = 1;
/* */
static void *
xmalloc (size_t size)
{
void *value = malloc (size);
if (value == NULL)
fprintf (stderr, "Alloc Memory error!\n");
return value;
}
/**/
void
my_mempool_init (void)
{
mempool = xmalloc (ps * PAGESIZE * sizeof(void*));
}
/**/
void*
my_alloc (int len)
{
void *tmp = xmalloc (len);
mempool[pcount] = tmp;
pcount = pcount + 1;
if (ps * PAGESIZE == pcount)
{
ps = ps + 1;
mempool = realloc (mempool, ps * PAGESIZE * sizeof(void*));
}
return tmp;
}
/**/
void
my_mempool_free (void)
{
for (int i = 0; i < pcount; i++)
free (mempool[i]);
free (mempool);
}
/**/
void
my_mempool_out_info (void)
{
printf ("PAGESIZE : %d\n", PAGESIZE);
printf ("Count : %d\n", pcount);
printf ("Pages : %d\n", ps);
printf ("Pointers : %d\n", ps * PAGESIZE);
}
/**/
int
my_strlen (char *str)
{
int len = 0;
while (*str != 0)
{
len = len + 1;
str++;
}
return len;
}
/**/
char*
my_strdup (char *str)
{
int len = my_strlen (str);
char *tmp = (char*) my_alloc (len * sizeof(char));
for (int i = 0; i < len; i++)
tmp[i] = str[i];
return tmp;
}
/**/
int
main (int argc, char *argv[])
{
my_mempool_init ();
for (int j = 0; j < 1000; j++)
{
char *tmp = my_strdup ("Not only a test here!");
}
my_mempool_out_info ();
my_mempool_free ();
return 0;
}
/* --(.v.)-- */
编译运行,通过,再用valgrind来检测一下,结果如下:
songvm@ubuntu:~/works/xdn/moo$ gcc mem.c -o mem
songvm@ubuntu:~/works/xdn/moo$ ./mem
PAGESIZE : 128
Count : 1000
Pages : 8
Pointers : 1024
songvm@ubuntu:~/works/xdn/moo$ valgrind --leak-check=yes ./mem
==3835== Memcheck, a memory error detector
==3835== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==3835== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==3835== Command: ./mem
==3835==
PAGESIZE : 128
Count : 1000
Pages : 8
Pointers : 1024
==3835==
==3835== HEAP SUMMARY:
==3835== in use at exit: 0 bytes in 0 blocks
==3835== total heap usage: 1,009 allocs, 1,009 frees, 58,888 bytes allocated
==3835==
==3835== All heap blocks were freed -- no leaks are possible
==3835==
==3835== For counts of detected and suppressed errors, rerun with: -v
==3835== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
将mempool封装到一个结构体中去
- 以上代码用到三个静态变量mempool, pcount, ps,用struct _Mempool结构体封装起来更规范一些!!!
- 再定义一个静态的结构体变量 static Mempool _mempool; 供程序调用。
修改代码如下:
/* filename: mema.c */
#include <stdio.h>
#include <stdlib.h>
/**/
#define PAGESIZE 128
/*
static void **mempool = NULL;
static int pcount = 0;
static int ps = 1;
*/
/**/
typedef struct _Mempool Mempool;
struct _Mempool {
void **pool;
int pcount, ps;
};
/**/
static Mempool _mempool;
/**/
static void *
xmalloc (size_t size)
{
void *value = malloc (size);
if (value == NULL)
fprintf (stderr, "Alloc Memory error!\n");
return value;
}
/**/
static Mempool *
get_mempool (void)
{
return &_mempool;
}
/**/
void
my_mempool_init (Mempool *mem)
{
mem->pcount = 0;
mem->ps = 1;
mem->pool = xmalloc (mem->ps * PAGESIZE * sizeof(void*));
}
/**/
void*
my_alloc (int len)
{
Mempool *mem = get_mempool();
void *tmp = xmalloc (len);
mem->pool[mem->pcount] = tmp;
mem->pcount = mem->pcount + 1;
if (((mem->ps) * PAGESIZE) == (mem->pcount))
{
mem->ps = mem->ps + 1;
mem->pool = realloc (mem->pool, ((mem->ps) * PAGESIZE) * sizeof(void*));
}
return tmp;
}
/**/
void
my_mempool_free (Mempool *mem)
{
for (int i = 0; i < mem->pcount; i++)
free (mem->pool[i]);
free (mem->pool);
}
/**/
void
my_mempool_out_info (Mempool *mem)
{
printf ("PAGESIZE : %d\n", PAGESIZE);
printf ("Count : %d\n", mem->pcount);
printf ("Pages : %d\n", mem->ps);
printf ("Pointers : %d\n", (mem->ps) * PAGESIZE);
}
/**/
int
my_strlen (char *str)
{
int len = 0;
while (*str != 0)
{
len = len + 1;
str++;
}
return len;
}
/**/
char*
my_strdup (char *str)
{
int len = my_strlen (str);
char *tmp = (char*) my_alloc (len * sizeof(char));
for (int i = 0; i < len; i++)
tmp[i] = str[i];
return tmp;
}
/**/
int
main (int argc, char *argv[])
{
Mempool *mem = get_mempool ();
my_mempool_init (mem);
for (int j = 0; j < 1000; j++)
{
char *tmp = my_strdup ("Not only a test here!");
}
my_mempool_out_info (mem);
my_mempool_free (mem);
return 0;
}
/* --(.v.)-- */
编译运行,用valgrind检查一下有无内存泄漏情况,结果如下:
songvm@ubuntu:~/works/xdn/moo$ gcc mema.c -o mema
songvm@ubuntu:~/works/xdn/moo$ ./mema
PAGESIZE : 128
Count : 1000
Pages : 8
Pointers : 1024
songvm@ubuntu:~/works/xdn/moo$ valgrind --leak-check=yes ./mema
==3913== Memcheck, a memory error detector
==3913== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==3913== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==3913== Command: ./mema
==3913==
PAGESIZE : 128
Count : 1000
Pages : 8
Pointers : 1024
==3913==
==3913== HEAP SUMMARY:
==3913== in use at exit: 0 bytes in 0 blocks
==3913== total heap usage: 1,009 allocs, 1,009 frees, 58,888 bytes allocated
==3913==
==3913== All heap blocks were freed -- no leaks are possible
==3913==
==3913== For counts of detected and suppressed errors, rerun with: -v
==3913== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
songvm@ubuntu:~/works/xdn/moo$
再分配1000个整数的数组指针并赋值测试,同时加上简单的注释
代码如下:
/* filename: memb.c */
#include <stdio.h>
#include <stdlib.h>
/* compile : gcc memb.c -o memb
run : ./memb
memcheck: valgrind --leak-check=yes ./memb */
/**/
#define PAGESIZE 128
/* define Mempool datatype */
typedef struct _Mempool Mempool;
struct _Mempool {
void **pool;
int pcount, ps;
};
/* the mempool here! */
static Mempool _mempool;
/* call malloc function and out error info */
static void *
xmalloc (size_t size)
{
void *value = malloc (size);
if (value == NULL)
fprintf (stderr, "Alloc Memory error!\n");
return value;
}
/* got the mempool! */
static Mempool *
get_mempool (void)
{
return &_mempool;
}
/* init the mempool */
void
my_mempool_init (Mempool *mem)
{
mem->pcount = 0;
mem->ps = 1;
mem->pool = xmalloc (mem->ps * PAGESIZE * sizeof(void*));
}
/* define alloc function myself */
void*
my_alloc (int len)
{
Mempool *mem = get_mempool();
void *tmp = xmalloc (len);
mem->pool[mem->pcount] = tmp;
mem->pcount = mem->pcount + 1;
if (((mem->ps) * PAGESIZE) == (mem->pcount))
{
mem->ps = mem->ps + 1;
mem->pool = realloc (mem->pool, ((mem->ps) * PAGESIZE) * sizeof(void*));
}
return tmp;
}
/* define free function myself */
void
my_mempool_free (Mempool *mem)
{
for (int i = 0; i < mem->pcount; i++)
free (mem->pool[i]);
free (mem->pool);
}
/* output mempool info */
void
my_mempool_out_info (Mempool *mem)
{
printf ("PAGESIZE : %d\n", PAGESIZE);
printf ("Count : %d\n", mem->pcount);
printf ("Pages : %d\n", mem->ps);
printf ("Pointers : %d\n", (mem->ps) * PAGESIZE);
}
/* define strlen funcfion myself */
int
my_strlen (char *str)
{
int len = 0;
while (*str != 0)
{
len = len + 1;
str++;
}
return len;
}
/* define strdup function myself return the str pointer
without free, my_mempool_free will free all */
char*
my_strdup (char *str)
{
int len = my_strlen (str);
char *tmp = (char*) my_alloc (len * sizeof(char));
for (int i = 0; i < len; i++)
tmp[i] = str[i];
return tmp;
}
/* ------------------------- */
/**/
int
main (int argc, char *argv[])
{
Mempool *mem = get_mempool ();
my_mempool_init (mem);
for (int j = 0; j < 1000; j++)
{
char *tmp = my_strdup ("Not only a test here!");
}
my_mempool_out_info (mem);
printf ("--------------------\n");
int *ip = (int*) my_alloc (1000 * sizeof(int));
for (int k = 0; k < 1000; k++)
ip[k] = k;
my_mempool_out_info (mem);
printf ("--------------------\n");
my_mempool_free (mem);
return 0;
}
/* --(.v.)-- */
编译运行,达到预期效果
songvm@ubuntu:~/works/xdn/moo$ gcc memb.c -o memb
songvm@ubuntu:~/works/xdn/moo$ ./memb
PAGESIZE : 128
Count : 1000
Pages : 8
Pointers : 1024
--------------------
PAGESIZE : 128
Count : 1001
Pages : 8
Pointers : 1024
--------------------
songvm@ubuntu:~/works/xdn/moo$ valgrind --leak-check=yes ./memb
==3944== Memcheck, a memory error detector
==3944== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==3944== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==3944== Command: ./memb
==3944==
PAGESIZE : 128
Count : 1000
Pages : 8
Pointers : 1024
--------------------
PAGESIZE : 128
Count : 1001
Pages : 8
Pointers : 1024
--------------------
==3944==
==3944== HEAP SUMMARY:
==3944== in use at exit: 0 bytes in 0 blocks
==3944== total heap usage: 1,010 allocs, 1,010 frees, 62,888 bytes allocated
==3944==
==3944== All heap blocks were freed -- no leaks are possible
==3944==
==3944== For counts of detected and suppressed errors, rerun with: -v
==3944== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
songvm@ubuntu:~/works/xdn/moo$
分成多个文件编译,为开发大一点的应用做准备
头文件mem.h代码如下:
/* filename: mem.h */
#ifndef MEM_HEADER
#define MEM_HEADER
/**/
#define PAGESIZE 128
/* define Mempool datatype */
typedef struct _Mempool Mempool;
struct _Mempool {
void **pool;
int pcount, ps;
};
Mempool * get_mempool (void);
void my_mempool_init (Mempool *mem);
void * my_alloc (int len);
void my_mempool_free (Mempool *mem);
void my_mempool_out_info (Mempool *mem);
int my_strlen (char *str);
char * my_strdup (char *str);
#endif/*MEM_HEADER*/
*相关功能实现mem.c代码如下:
/* filename: mem.c */
#include <stdio.h>
#include <stdlib.h>
#include "mem.h"
/* the mempool here! */
static Mempool _mempool;
/* call malloc function and out error info */
static void *
xmalloc (size_t size)
{
void *value = malloc (size);
if (value == NULL)
fprintf (stderr, "Alloc Memory error!\n");
return value;
}
/* got the mempool! */
Mempool *
get_mempool (void)
{
return &_mempool;
}
/* init the mempool */
void
my_mempool_init (Mempool *mem)
{
mem->pcount = 0;
mem->ps = 1;
mem->pool = xmalloc (mem->ps * PAGESIZE * sizeof(void*));
}
/* define alloc function myself */
void*
my_alloc (int len)
{
Mempool *mem = get_mempool();
void *tmp = xmalloc (len);
mem->pool[mem->pcount] = tmp;
mem->pcount = mem->pcount + 1;
if (((mem->ps) * PAGESIZE) == (mem->pcount))
{
mem->ps = mem->ps + 1;
mem->pool = realloc (mem->pool, ((mem->ps) * PAGESIZE) * sizeof(void*));
}
return tmp;
}
/* define free function myself */
void
my_mempool_free (Mempool *mem)
{
for (int i = 0; i < mem->pcount; i++)
free (mem->pool[i]);
free (mem->pool);
}
/* output mempool info */
void
my_mempool_out_info (Mempool *mem)
{
printf ("PAGESIZE : %d\n", PAGESIZE);
printf ("Count : %d\n", mem->pcount);
printf ("Pages : %d\n", mem->ps);
printf ("Pointers : %d\n", (mem->ps) * PAGESIZE);
}
/* define strlen funcfion myself */
int
my_strlen (char *str)
{
int len = 0;
while (*str != 0)
{
len = len + 1;
str++;
}
return len;
}
/* define strdup function myself return the str pointer
without free, my_mempool_free will free all */
char*
my_strdup (char *str)
{
int len = my_strlen (str);
char *tmp = (char*) my_alloc (len * sizeof(char));
for (int i = 0; i < len; i++)
tmp[i] = str[i];
return tmp;
}
/* ----- mem.c ----- */
- 测试功能文件tmem.c代码如下:
/* filename: tmem.c */
#include <stdio.h>
#include <stdlib.h>
#include "mem.h"
/* compile : gcc mem.c tmem.c -o tmem
run : ./tmem
memcheck: vargrind --leak-check=yes ./tmem */
/**/
int
main (int argc, char *argv[])
{
Mempool *mem = get_mempool ();
my_mempool_init (mem);
for (int j = 0; j < 1000; j++)
{
char *tmp = my_strdup ("Not only a test here!");
}
my_mempool_out_info (mem);
printf ("--------------------\n");
int *ip = (int*) my_alloc (1000 * sizeof(int));
for (int k = 0; k < 1000; k++)
ip[k] = k;
my_mempool_out_info (mem);
printf ("--------------------\n");
my_mempool_free (mem);
return 0;
}
/* --(.v.)-- */
编译运行,结果如预期:
gwsong@ubuntu:~/works/zoo/moo$ gcc mem.c tmem.c -o tmem
gwsong@ubuntu:~/works/zoo/moo$ ls
memb memb.c mem.c mem.c~ mem.h mem.h~ tmem tmem.c tmem.c~
gwsong@ubuntu:~/works/zoo/moo$ ./tmem
PAGESIZE : 128
Count : 1000
Pages : 8
Pointers : 1024
--------------------
PAGESIZE : 128
Count : 1001
Pages : 8
Pointers : 1024
--------------------
gwsong@ubuntu:~/works/zoo/moo$ valgrind --leak-check=yes ./tmem
==3639== Memcheck, a memory error detector
==3639== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==3639== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==3639== Command: ./tmem
==3639==
PAGESIZE : 128
Count : 1000
Pages : 8
Pointers : 1024
--------------------
PAGESIZE : 128
Count : 1001
Pages : 8
Pointers : 1024
--------------------
==3639==
==3639== HEAP SUMMARY:
==3639== in use at exit: 0 bytes in 0 blocks
==3639== total heap usage: 1,010 allocs, 1,010 frees, 62,888 bytes allocated
==3639==
==3639== All heap blocks were freed -- no leaks are possible
==3639==
==3639== For counts of detected and suppressed errors, rerun with: -v
==3639== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
gwsong@ubuntu:~/works/zoo/moo$
下一步研究一下数据结构!!!