C言語で簡易メモリ管理
Linux Kernelのリスト構造を参考に作成。
環境:CentOS 6, gcc version 4.4.7
mempool.h
#ifndef _MEMPOOL_H_
#define _MEMPOOL_H_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <stddef.h>
#define EASY_ELECTORIC_FENCE (0x123456789)
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
#define GET_ENTRY(ptr,type,member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
#define Malloc(size) \
__Malloc(size, __FILE__, __LINE__)
#define Free(ptr) \
__Free(ptr)
struct mem_list {
struct mem_list *prev;
struct mem_list *next;
};
typedef struct {
struct mem_list head;
int32_t entry_count;
} MemListHead_t;
typedef struct {
struct mem_list list;
int64_t fence; /* electoric fence */
char file[64]; /* ファイル名 */
int32_t line; /* 行数 */
struct timeval tv; /* 取得時刻 */
int32_t size; /* memory size */
void* address; /* dataのアドレス */
uint8_t data[0]; /* ユーザに渡すポインタ */
} MemListEntry_t;
static inline memlist_init(
struct mem_list *head)
{
head->prev = head;
head->next = head;
}
static inline memlist_add_tail(
struct mem_list *entry,
struct mem_list *head)
{
head->prev->next = entry;
entry->next = head;
entry->prev = head->prev;
head->prev = entry;
}
static inline memlist_del(
struct mem_list *entry,
struct mem_list *head)
{
entry->prev->next = entry->next;
entry->next->prev = entry->prev;
entry->next = (struct mem_list *)0xdeaddead;
entry->prev = (struct mem_list *)0xdeaddead;
}
extern void* __Malloc(size_t size, char* file, size_t line);
extern void __Free(void* ptr);
#endif /* _MEMPOOL_H_ */
mempool.c
#include "mempool.h"
extern MemListHead_t MngMem;
void* __Malloc(
size_t size,
char* file,
size_t line)
{
void* ptr = NULL;
MemListEntry_t* entry =
(MemListEntry_t*) malloc(sizeof(*entry)+size);
if (NULL != entry) {
entry->fence = EASY_ELECTORIC_FENCE;
entry->size = size;
snprintf(entry->file, sizeof(entry->file)-1, "%s", file);
entry->line = line;
gettimeofday(&entry->tv, NULL);
entry->address = &entry->data[0];
memlist_add_tail(&entry->list, &MngMem.head);
ptr = &entry->data[0];
}
return ptr;
}
void __Free(
void* ptr)
{
MemListEntry_t* entry =
(MemListEntry_t*)((uint8_t*)ptr - sizeof(MemListEntry_t));
if(!(entry->address == ptr && EASY_ELECTORIC_FENCE != entry->fence)) {
/* memory currupted or invalid address */
}
memlist_del(&entry->list, &MngMem.head);
free(entry);
}
memtest.c (動作確認用のソースコード)
#include "mempool.h"
MemListHead_t MngMem;
typedef struct {
int a;
int b;
int c;
int d;
int e[1024];
} testData_t;
int main(int argc, char *argv[])
{
/* メモリ管理リスト初期化 */
memlist_init(&MngMem.head);
/* メモリ領域を確保 */
testData_t *dat1 =
(testData_t* )Malloc(sizeof(*dat1));
testData_t *dat2 =
(testData_t* )Malloc(sizeof(*dat2)+1);
testData_t *dat3 =
(testData_t* )Malloc(sizeof(*dat3)+2);
/* dat1,2,3がメモリ管理リストに追加されているか確認 */
struct mem_list *p;
printf("##### BEFORE #####\n");
printf("file:line, size, fence, address\n");
printf("-------------------------------\n");
list_for_each(p, &(MngMem.head)) {
MemListEntry_t *gp = GET_ENTRY(p, MemListEntry_t, list);
printf("%s:%u, %d, %#llx, %p\n",
gp->file, gp->line, gp->size, gp->fence, gp->address);
}
/* dat2の削除 */
Free(dat2);
/* メモリ管理リストからdat2のエントリが消えているか確認 */
printf("##### AFTER1 #####\n");
printf("file:line, size, fence, address\n");
printf("-------------------------------\n");
list_for_each(p, &(MngMem.head)) {
MemListEntry_t *gp = GET_ENTRY(p, MemListEntry_t, list);
printf("%s:%u, %d, %#llx, %p\n",
gp->file, gp->line, gp->size, gp->fence, gp->address);
}
/* dat1, dat3の削除 */
Free(dat1);
Free(dat3);
/* メモリ管理リストからエントリがすべて消えているか確認 */
printf("##### AFTER2 #####\n");
printf("file:line, size, fence, address\n");
printf("-------------------------------\n");
list_for_each(p, &(MngMem.head)) {
MemListEntry_t *gp = GET_ENTRY(p, MemListEntry_t, list);
printf("%s:%u, %d, %#llx, %p\n",
gp->file, gp->line, gp->size, gp->fence, gp->address);
}
return 0;
}
Makefile
memtest: memtest.o mempool.o
gcc -g -o memtest memtest.o mempool.o
memtest.o: memtest.c mempool.h
gcc -g -c memtest.c
mempool.o: mempool.c mempool.h
gcc -g -c mempool.c
clean: *.o
rm -f *.o
動作確認
$ make
gcc -g -c memtest.c
gcc -g -c mempool.c
gcc -g -o memtest memtest.o mempool.o
$
$ ./memtest
##### BEFORE #####
file:line, size, fence, address
-------------------------------
memtest.c:18, 4112, 0x123456789, 0x6b7090
memtest.c:20, 4113, 0x123456789, 0x6b8130
memtest.c:22, 4114, 0x123456789, 0x6b91d0
##### AFTER1 #####
file:line, size, fence, address
-------------------------------
memtest.c:18, 4112, 0x123456789, 0x6b7090
memtest.c:22, 4114, 0x123456789, 0x6b91d0
##### AFTER2 #####
file:line, size, fence, address
-------------------------------
コメント