Arenas are the simplest allocation scheme ever.
// Start of frame
void *arena = malloc(LOTS_OF_MEMORY);
void *next_ptr = arena;
// Allocate something
object = *next_ptr; // return that value
next_ptr = object_size + alignment; // crash if out of memory
// End of frame
free(arena);
By the way, such "separate complex ad hoc" memory allocation schemes are the reason why manual memory management is faster than garbage collection. If you did everything with malloc(), it would be slower (unless the GC language allocates much more than C, which they often do).