🟩 Heap Allocation, Custom allocators, Virtual Memory, Buffer, Segment
SaneCppMemory.h is library tracking and limiting runtime / dynamic allocations through the use of custom allocators.
- Note
- If a library doesn't directly or indirectly depend on the Memory library, you can assume that it will not do any runtime / dynamic allocation.
Most classes have been originally part of the Foundation library.
Dependencies

Features
Classes
Class | Description |
SC::Buffer | An heap allocated byte buffer that can optionally use an inline buffer. |
SC::Memory | Centralized functions to allocate, reallocate and deallocate memory. |
SC::VirtualMemory | Reserves a contiguous slice of virtual memory committing just a portion of it. |
SC::Globals | Customizable thread-local and global variables for memory handling. |
SC::String | A non-modifiable owning string with associated encoding. |
SC::SmallString | String with compile time configurable inline storage (small string optimization) |
Status
🟩 Usable
The library is solid. The Buffer implementation has been evolved and fine tuned to be minimal but effective.
Description
Memory library helps tracking and limit runtime / dynamic allocations through the use of custom allocators. A classic dynamically expandable binary buffer SC::Buffer is provided and it's largely shared to form the more object model oriented SC::Vector class from Containers Library.
All allocations throughout all downstream dependant libraries are centrally tracked by the SC::Globals class, that also allows re-defining custom thread-local allocators.
Such allocators can be just fixed buffers, regular heap memory or reserved SC::VirtualMemory using only limited amounts of Physical memory.
Buffer
An heap allocated byte buffer that can optionally use an inline buffer.
- See also
- SC::SmallBuffer to use an inline buffer that can optionally become heap allocated as needed.
- Note
- This class (and SC::SmallBuffer) reduces needs for the header-only SC::Vector (from Containers). SC::Buffer avoids some compile time / executable size bloat because it's not header only.
Example:
bool funcRequiringBuffer(Buffer& buffer)
{
for (size_t idx = 0; idx < buffer.size(); ++idx)
{
if (buffer[idx] != 123)
return false;
}
return true;
}
void BufferTest::basic()
{
Buffer buffer;
buffer.clear();
funcRequiringBuffer(buffer);
SmallBuffer<128> smallBuffer;
smallBuffer = buffer;
funcRequiringBuffer(smallBuffer);
Buffer buffer2;
smallBuffer =
move(buffer2);
}
String
A non-modifiable owning string with associated encoding.
SC::String is (currently) implemented as a SC::Vector with the associated string encoding. A SC::StringSpan can be obtained from it calling SC::String::view method but it's up to the user making sure that the usage of such SC::StringSpan doesn't exceed lifetime of the SC::String it originated from (but thankfully Address Sanitizer will catch the issue if it goes un-noticed).
SmallString
String with compile time configurable inline storage (small string optimization)
- Template Parameters
-
N | number of chars to reserve in inline storage |
Memory
Centralized functions to allocate, reallocate and deallocate memory.
VirtualMemory
Reserves a contiguous slice of virtual memory committing just a portion of it.
This class is useful on 64-bit systems where the address space is so large that it's feasible reserving large chunks of memory to commit and de-commit (shrink) as needed.
Reservation ensures that the returned address will not change and will be sized in multiples of system page size.
- Note
- Memory must be committed in order to be read or written, occupying physical memory pages.
- Warning
- This class has no defined destructor so memory MUST be released calling VirtualMemory::release
const size_t moreThanOnePageSize = VirtualMemory::getPageSize() + 1024;
const size_t lessThanOnePageSize = VirtualMemory::getPageSize() - 1024;
void* reference = Memory::allocate(moreThanOnePageSize, 1);
memset(reference, 1, moreThanOnePageSize);
auto releaseLater =
MakeDeferred([&] { Memory::release(reference); });
SC_TEST_EXPECT(virtualMemory.reserve(2 * VirtualMemory::getPageSize()));
char* memory = static_cast<char*>(virtualMemory.memory);
memset(memory, 1, lessThanOnePageSize);
memset(memory + lessThanOnePageSize, 1, moreThanOnePageSize - lessThanOnePageSize);
Globals
Customizable thread-local and global variables for memory handling.
This class holds pointers to systems that must be globally available, like the memory allocator. It allows "stacking" different Globals through a push / pop mechanism, connecting them through a linked list. The Default allocator is automatically setup and uses standard malloc
, realloc
, free
for allocations.
- Note
- Globals use no locking mechanism so they are thread-unsafe. Every method however requires a Globals::Type parameter that can be set to Globals::ThreadLocal to avoid such issues.
Example (Fixed Allocator):
alignas(
uint64_t)
char stackMemory[256] = {0};
FixedAllocator fixedAllocator = {stackMemory, sizeof(stackMemory)};
Globals globals = {fixedAllocator};
Globals::push(Globals::Global, globals);
Buffer& buffer = *Globals::get(Globals::Global).allocator.create<Buffer>();
(void)buffer.append({"ASDF"});
Globals::pop(Globals::Global);
Example (Virtual Allocator):
VirtualMemory virtualMemory;
VirtualAllocator virtualAllocator = {virtualMemory};
Globals virtualGlobals = {virtualAllocator};
Globals::push(Globals::Global, virtualGlobals);
Buffer& buffer = *Globals::get(Globals::Global).allocator.create<Buffer>();
(void)buffer.append({"ASDF"});
Globals::pop(Globals::Global);
Example (Memory dump):
struct NestedStruct
{
};
struct ComplexStruct
{
int someField = 0;
NestedStruct nestedStruct;
};
Globals::push(Globals::Global, globals);
ComplexStruct&
object = *allocator.
create<ComplexStruct>();
object.someField = 42;
object.singleString = "ASDF";
object.someStrings = {"First", "Second"};
SC_TEST_EXPECT(
object.nestedStruct.someMap.insertIfNotExists({
"1", 1}));
SC_TEST_EXPECT((
size_t(memoryDump.data()) %
alignof(ComplexStruct)) == 0);
Globals::pop(Globals::Global);
const ComplexStruct& readonly = *start_lifetime_as<const ComplexStruct>(span);
ComplexStruct modifiable = readonly;
modifiable.someStrings[0] = "First modified";
Blog
These blogs have been written before the split from Foundation into the Memory library:
These blog posts have been written after the split from foundation:
Roadmap
🟦 Complete Features:
- Things will be added as needed
💡 Unplanned Features:
- Note
- In Principles there is a rule that discourages allocations of large number of tiny objects and also creating systems with unclear or shared memory ownership. For this reason this library is missing Smart Pointers.
Statistics
Type | Lines Of Code | Comments | Sum |
Headers | 433 | 398 | 831 |
Sources | 1037 | 219 | 1256 |
Sum | 1470 | 617 | 2087 |