It's very easy to use:
- include "memory.c" and "memory.h" in your project;
- call "MemoryStart" in "main" to initialize the GC;
- use "MemoryAlloc" instead of "malloc" to get memory (you don't need to use "free" anymore).
Makes use of most of the 8KB RAM area (the rest is for global variables as usual) and calls "MemoryClean", a "mark & sweep" algorithm, when memory is full. I won't claim this is "zero-overhead", in fact there's a slight lag when the algorithm is called, but it does work for CC65 and the NES, compared to other libraries on the internet. You can also manually call MemoryClean whenever you want, for example during scene change, to manually free unused memory.
I've attached the testing example I worked on, so you can give it a shot too!
memory.h:
Code: Select all
#ifndef MEMORY_H
#define MEMORY_H
#include "stdfx.h"
void MemoryStart();
void* MemoryAlloc(size_t size);
void MemoryClean();
#endif
Code: Select all
#include "memory.h"
#define STACK_MIN 0x0500
#define STACK_MAX 0x0800
#define RAM_MIN 0x6000
#define MEMORY_MIN 0x6100
#define MEMORY_MAX 0x8000
typedef struct
{
void* ptr;
size_t size;
void* next;
bool marked;
} MemoryObject;
MemoryObject* memoryList = NULL;
void MemoryDeleteByPrevious(MemoryObject* previous)
{
MemoryObject* current;
if(previous != NULL)
{
current = previous->next;
previous->next = current->next;
}
else
{
current = memoryList;
memoryList = current->next;
}
free(current->ptr);
free(current);
}
void MemoryMarkArea(void* start, void* finish)
{
void** ptr;
MemoryObject* object;
for(ptr = start; ptr < finish; ptr++)
{
if(*ptr < (void*)MEMORY_MIN || *ptr >= (void*)MEMORY_MAX) continue;
object = memoryList;
while(object != NULL)
{
if(object->marked == false && *ptr == object->ptr)
{
object->marked = true;
MemoryMarkArea(object->ptr, (void*)((size_t)object->ptr + object->size));
break;
}
object = object->next;
}
}
}
void MemoryMark()
{
MemoryMarkArea((void*)STACK_MIN, (void*)STACK_MAX);
MemoryMarkArea((void*)RAM_MIN, (void*)MEMORY_MIN);
}
void MemorySweep()
{
MemoryObject* previous;
MemoryObject* current;
previous = NULL;
current = memoryList;
while(current != NULL)
{
if(current->marked == false)
{
MemoryDeleteByPrevious(previous);
current = (previous != NULL) ? previous->next : memoryList;
}
else
{
current->marked = false;
previous = current;
current = current->next;
}
}
}
void MemoryClean()
{
MemoryMark();
MemorySweep();
}
void MemoryAdd(MemoryObject* object, MemoryObject* previous, MemoryObject* current)
{
if(current != NULL)
{
MemoryAdd(object, current, current->next);
}
else
{
current = object;
current->next = NULL;
current->marked = false;
if(previous != NULL) previous->next = current;
else memoryList = current;
}
}
void* MemoryAlloc(size_t size)
{
void* ptr = NULL;
MemoryObject* object = NULL;
MemoryObject* previous = NULL;
MemoryObject* current = NULL;
while(true)
{
ptr = malloc(size);
if(ptr == NULL) MemoryClean();
else break;
}
while(true)
{
object = malloc(sizeof(MemoryObject));
if(object == NULL) MemoryClean();
else break;
}
current = memoryList;
while(current != NULL)
{
previous = current;
current = current->next;
}
current = object;
current->ptr = ptr;
current->size = size;
current->next = NULL;
current->marked = false;
if(previous != NULL) previous->next = current;
else memoryList = current;
return ptr;
}
void MemoryStart()
{
_heapadd ((void*)MEMORY_MIN, MEMORY_MAX - MEMORY_MIN);
}