Runtime
Memory
There are cases where garbage collection is not desirable. Therefor, we cannot have gc by default.
So I think the way this will be handled is that the Runtime has single allocator/deallocator. This can be gc, manual or hybrid.
One complication that arises is that libraries will need a way to deal with all three models. Modules can safely make an assumption about their runtime.
I think the way to do this is with pointer kinds. A pointer type includes if it is managed or unmanaged. And anything that is holding a managed pointer will need to interact the GC by registering and deregistering it's managed pointers.
Debug
For debugging (particularly manual memory debugging) we can use a smart allocator. It will run as a gc even when no gc is used. When memory is deallocated, it will actually be marked but held until the next gc cycle. We can then find dangling pointers or memory leaks.
If the size of a pointer can be adjusted, we can do a lock-and-key system as well baked right into the debug pointer.