Implement a simple Memory Allocation Module with simple fragment functions
/* Start of main. c */
# Include "memory. h"
# Define MEMBODY_SIZE 640
Char membody [MEMBODY_SIZE] = {0 ,};
Int main ()
{
Void * mem1, * mem2, * mem3;
Int I;
Printf ("main !!! \ N ");
Simple_mem_init (membody, MEMBODY_SIZE );
Apsaradb for mem1 = simple_new (200 );
Apsaradb for mem2 = simple_new (200 );
Mem3 = simple_new (200 );
Simple_delete (mem1 );
Simple_delete (mem2 );
Simple_delete (mem3 );
Apsaradb for mem1 = simple_new (300 );
Simple_delete (mem1 );
For (I = 0; I ++ ){
If (! Simple_new (10 ))
Break;
}
Return 0;
}
/* End of Main. C */
/* Start of memory. H */
# Ifndef memory_h
# Define memory_h
/* Not very useful, but only some defines */
# Include "common. H"
Void simple_delete (char * data );
Void simple_delete_array (char * data );
Void simple_memset (char * data, char Val, int32 size );
Char * simple_new (int32 size );
Bool simple_mem_init (char * MEM, int32 size );
# Endif
/* End of memory. H */
/* Start of memory. C */
# Include "memory. h"
// Sizeof (MEM_ALLOC_INFO) must be mem_slice_size aligned
Typedef struct {
Int32 size;
} MEM_ALLOC_INFO;
# Define mem_slice_size 4 // must be greater than 4 and shoule be multile of 4
# Define mem_slice_size_is_2_index // define this if mem_slice_size = 2 ^ n
# Ifdef mem_slice_size_is_2_index
// Mem_slice_size = 2 ^ mem_slice_size_shift
# Define mem_slice_size_shift 2
# Endif
# Define bitsof (type) (int32) (sizeof (type) <3 ))
// The last on is greater than mem_block_free_list_size * mem_slice_size
# Define mem_block_free_list_size (0x80)
# Ifdef mem_slice_size_is_2_index
# Define roundup_2_mem_slice_size (size) + mem_slice_size-1) & (-mem_slice_size ))
# Else
# Define roundup_2_mem_slice_size (size) + mem_slice_size-1)-(size) + mem_slice_size-1) % mem_slice_size ))
# Endif
// {4, 8, 12, 16 ...}
// The last is a list that with various size but greater
// Mem_slice_size * mem_block_free_list_size
Static char * mem_block_free_list [mem_block_free_list_size] = {0 ,};
Static unsigned char mem_valible_idx_flag [mem_block_free_list_size/(bitsof (char)] = {0 ,};
// Stats
Static int32 mem_block_free_cnt_list [mem_block_free_list_size] = {0 ,};
Static int32 mem_block_alloc_cnt_list [mem_block_free_list_size] = {0 ,};
Static int32 mem_block_alloc_fail_cnt_list [mem_block_free_list_size] = {0 ,};
Static void add_new_block (char * mem, int32 size );
Static char * simple_new_internal (int32 alloc_size );
Static char * malloc_by_idx (int32 idx, int32 alloc_size );
Static int32 collect_mem (char * m );
Static void mem_block_set (int32 idx, char * mem );
Static void process_partion_mem (char * mem, int32 size );
Static char * membody;
Static int32 membody_size;
# Define mem_used_flag 0x1
# Define mem_flag_mask 0x3
# Define mem_size (mem )\
(* (Int32 *) (mem) & (-4 ))
# Define mem_is_used (mem )\
(* (Int32 *) (mem) & mem_used_flag)
# Define mem_set_freed (mem )\
(* (Int32 *) (mem) = (* (int32 *) (mem) & (-2 ));
# Define mem_set_used (mem )\
(* (Int32 *) (mem) = (* (int32 *) (mem) | mem_used_flag)
# Define mem_size_idx (idx )\
(Idx) * (mem_slice_size ))
# Define mem_block (idx )\
Mem_block_free_list [idx]
# Define mem_next (mem )\
(* (Int32 *) (mem + sizeof (int32 )))
# Define mem_next_get (mem )\
(Char *) mem_next (mem)
# Define mem_next_set (mem, next )\
Mem_next (mem) = next
// (Mem_slice_size = 4)
Static int32 mem_idx (int32 size)
{
# Ifdef mem_slice_size_is_2_index
Int32 idx = (size)> mem_slice_size_shift );
# Else
Int32 idx = size/mem_slice_size;
# Endif
If (idx> = mem_block_free_list_size)
Idx = mem_block_free_list_size-1;
Return idx;
}
# Define mem_size_idx_min \
Mem_idx (sizeof (MEM_ALLOC_INFO) + mem_slice_size-1)
Static void mem_size_set (char * mem, int32 size)
{
Size = size | (* (int32 *) (mem) & mem_flag_mask );
(* (Int32 *) (mem) = size;
}
Static void mem_block_set (int32 idx, char * mem)
{
Int32 x = idx> 3;
Int32 y = idx & 7;
Mem_block_free_list [idx] = mem;
If (mem! = NULL ){
Mem_valible_idx_flag [x] =
Mem_valible_idx_flag [x] | (1 <y );
} Else {
Mem_valible_idx_flag [x] =
Mem_valible_idx_flag [x] & (~ (1 <y ));
}
}
Static void alloc_stats (int32 size)
{
Mem_block_alloc_cnt_list [mem_idx (size)] ++;
}
Static void alloc_fail_stats (int32 size)
{
Mem_block_alloc_fail_cnt_list [mem_idx (size)] ++;
}
Static void free_stats (int32 size)
{
Mem_block_free_cnt_list [mem_idx (size)] ++;
}
// The first funtion must be called when memmory alloc works
Bool simple_mem_init (char * mem, int32 size)
{
If (! Mem |! Size)
Return false;
Membody = mem;
Membody_size = size;
Add_new_block (mem, size );
Return true;
}
Static void mem_set_alloc_inf (char * mem, int32 size)
{
Mem_size_set (mem, size );
Mem_set_used (mem );
}
Static bool mem_in (char * addr)
{
If (ADDR <membody | ADDR> = membody + membody_size)
Return false;
Return true;
}
// Mem is in free list
Static void remove_free_mem (char * MEm)
{
Char * pre = 0, * cur = NULL;
Int32 idx = mem_idx (mem_size (MEM ));
Cur = mem_block (idx );
While (cur! = MEm ){
Pre = cur;
Cur = mem_next_get (cur );
}
If (cur! = MEm ){
Crashme ("Invalid Data !!! ");
Return;
}
If (pre! = NULL)
Mem_next_set (pre, mem_next_get (cur ));
Else if (cur = mem_block (idx )){
Char * next = mem_next_get (cur );
Mem_block_set (idx, mem_next_get (cur ));
}
Mem_next_set (mem, NULL );
}
Static void merge_mem (char * mem)
{
Remove_free_mem (mem + mem_size (mem ));
Mem_size_set (mem, mem_size (mem) + mem_size (mem )));
}
Static int32 collect_mem (char * m)
{
Int32 size = mem_size (m );
If (! Mem_is_used (m ))
Remove_free_mem (m );
While (mem_in (m + size)
&&! Mem_is_used (m + size )){
Merge_mem (m );
Size = mem_size (m );
}
Add_new_block (m, size );
Return size;
}
Void simple_delete (char * data)
{
Char * m = (char *) data-sizeof (MEM_ALLOC_INFO );
If (! Mem_in (m)
|! Mem_is_used (m ))
Return;
Free_stats (mem_size (m ));
Collect_mem (m );
}
Void simple_delete_array (char * data)
{
Simple_delete (data );
}
Void simple_memset (char * data,
Char val, int32 size)
{
Int32 I;
For (I = 0; I <size; I ++)
Data [I] = val;
}
Static void add_new_block (char * mem, int32 size)
{
Int32 idx = mem_idx (size );
Mem_next_set (mem, mem_block (idx ));
Mem_block_set (idx, mem );
Mem_set_freed (mem );
Mem_size_set (mem, size );
}
Static char * post_alloc (int32 idx,
Int32 alloc_size)
{
# Ifdef mem_slice_size_is_2_index
Int32 remain = (idx <mem_slice_size_shift)-alloc_size;
# Else
Int32 remain = idx * mem_slice_size-alloc_size;
# Endif
Char * memnext = mem_next_get (mem_block (idx ));
Add_new_block (mem_block (idx) + alloc_size,
Remain );
Return memnext;
}
Static char * find_best_match (int32 alloc_size)
{
Char * nextmem;
Int32 diff = 0x7fffffff;
Char * bestmem = NULL;
Char * pre1 = NULL, * pre2 = NULL;
For (nextmem = mem_block (mem_block_free_list_size-1 );
Nextmem! = NULL;
Pre1 = nextmem, nextmem = mem_next (nextmem )){
If (mem_size (nextmem)> = alloc_size
& (Mem_size (nextmem)-alloc_size) <diff ){
Pre2 = pre1;
Diff = mem_size (nextmem)-alloc_size;
Bestmem = nextmem;
If (diff <0x10)
Break;
}
}
If (bestmem! = NULL ){
If (pre2! = NULL)
Mem_next_set (pre2, mem_next_get (bestmem ));
Else
Mem_block_set (mem_block_free_list_size-1, mem_next_get (bestmem ));
}
Return bestmem;
}
Static int32 collect (int32 idx, int32 alloc_size)
{
Char * m = mem_block (idx );
Int32 size;
While (m! = NULL ){
Size = collect_mem (m );
If (size> = alloc_size)
Return mem_idx (size );
M = mem_next_get (m );
}
Return-1;
}
// When compact and find a memory bigger than alloc_size
// Just return idx
Static int32 mem_compact (int32 alloc_size)
{
Int32 idx;
Int32 validi = 0;
For (validi = (mem_block_free_list_size> 3)-1;
Validi> = 0;
Validi --){
If (mem_valible_idx_flag [validi] = 0)
Continue;
For (idx = (validi + 1) <3)-1;
Idx >=( validi <3 );
Idx --){
If (mem_block (idx )! = NULL ){
Int32 result = collect (idx, alloc_size );
If (result> = 0)
Return result;
}
}
}
Return-1;
}
Static char * big_mem_alloc (int32 alloc_size)
{
Char * bestmem = find_best_match (alloc_size );
If (! Bestmem ){
Int32 idx = mem_compact (alloc_size );
If (idx> = 0)
Return malloc_by_idx (idx, alloc_size );
Alloc_fail_stats (alloc_size );
CrashMe ("out of memory ");
Return NULL;
}
Process_partion_mem (bestmem + alloc_size, mem_size (bestmem)-alloc_size );
Mem_set_alloc_inf (bestmem, alloc_size );
Return bestmem + sizeof (mem_alloc_info );
}
Static int32 next_valible_idx (int32 idx)
{
Int32 I, CNT;
For (I = idx/bitsof (char); I <(mem_block_free_list_size> 3); I ++ ){
If (mem_valible_idx_flag [I]! = 0
& Mem_valible_idx_flag [I] >=( 1 <(idx & 7 ))){
CNT = (I <3) + (idx & 7 );
Return CNT;
}
Idx = 0;
}
Return mem_block_free_list_size-1; // always try last item
}
Static void process_partion_mem (char * mem, int32 size)
{
If (size <= 0)
Return;
Mem_size_set (mem, size );
Mem_set_used (mem );
Collect_mem (mem );
}
Static char * malloc_by_idx (int32 idx, int32 alloc_size)
{
Char * result = 0;
If (idx = mem_block_free_list_size-1)
Return big_mem_alloc (alloc_size );
Result = mem_block (idx );
Mem_block_set (idx, mem_next_get (mem_block (idx )));
# Ifdef mem_slice_size_is_2_index
Process_partion_mem (result + alloc_size,
(Idx <mem_slice_size_shift)-alloc_size );
# Else
Process_partion_mem (result + alloc_size,
Idx * mem_slice_size-alloc_size );
# Endif
Mem_set_alloc_inf (result,
Alloc_size );
Return result + sizeof (mem_alloc_info );
}
Static char * simple_new_internal (int32 alloc_size)
{
Int32 idx = mem_idx (alloc_size );
Int32 tmp = next_valible_idx (idx );
Idx = tmp> idx? Tmp: idx;
Alloc_stats (alloc_size );
For (idx; idx <mem_block_free_list_size-1; idx ++ ){
If (mem_block (idx )! = NULL ){
Break;
}
}
Return malloc_by_idx (idx, alloc_size );
}
Char * simple_new (int32 size)
{
Char * result = 0;
Int32 alloc_size = size + sizeof (MEM_ALLOC_INFO );
If (! Size)
Return NULL;
Alloc_size = roundup_2_mem_slice_size (alloc_size );
Return simple_new_internal (alloc_size );
}
/* End of memory. C */