Sane C++ Libraries
C++ Platform Abstraction Libraries
Loading...
Searching...
No Matches
SC::VirtualMemory Struct Reference

Reserves a contiguous slice of virtual memory committing just a portion of it. More...

#include <VirtualMemory.h>

Public Member Functions

bool reserve (size_t maxCapacityInBytes)
 Reserves a large block of virtual memory of size maxCapacityInBytes.
 
bool release ()
 Reclaims the entire virtual memory block (reserved with VirtualMemory::reserve)
 
bool commit (size_t newCapacityBytes)
 Ensures at least newCapacityBytes to be committed / accessible from the large maxCapacityInBytes block.
 
bool shrink (size_t newCapacityBytes)
 Reclaims all unused pages past newCapacityBytes (previously committed with VirtualMemory::commit)
 

Static Public Member Functions

static size_t roundUpToPageSize (size_t size)
 Round up the passed in size to system memory page size.
 
static size_t getPageSize ()
 Obtains system memory page size.
 

Public Attributes

size_t reservedBytes = 0
 Maximum amount of reserved memory that can be committed.
 
size_t committedBytes = 0
 Current amount of committed memory.
 
void * memory = nullptr
 Pointer to start of reserved memory.
 

Detailed Description

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
// This test uses two pages initially and just one page later
// On Windows and Linux default Page size is typically 4Kb
// On macOS default page size is typically 16 Kb
const size_t moreThanOnePageSize = VirtualMemory::getPageSize() + 1024;
const size_t lessThanOnePageSize = VirtualMemory::getPageSize() - 1024;
SC_TEST_EXPECT(lessThanOnePageSize > 0); // sanity check just in case
void* reference = Memory::allocate(moreThanOnePageSize, 1);
memset(reference, 1, moreThanOnePageSize);
auto releaseLater = MakeDeferred([&] { Memory::release(reference); });
VirtualMemory virtualMemory;
// Reserve 2 pages of virtual memory
SC_TEST_EXPECT(virtualMemory.reserve(2 * VirtualMemory::getPageSize()));
// Request to use less than one page of virtual memory
SC_TEST_EXPECT(virtualMemory.commit(lessThanOnePageSize));
char* memory = static_cast<char*>(virtualMemory.memory);
// Check that memory is writable and fill it with 1
memset(memory, 1, lessThanOnePageSize);
// Let's now extend this block from one to two pages
SC_TEST_EXPECT(virtualMemory.commit(moreThanOnePageSize));
// Fill the "newly committed" pages with 1
memset(memory + lessThanOnePageSize, 1, moreThanOnePageSize - lessThanOnePageSize);
// Make sure that previously reserved address is stable
SC_TEST_EXPECT(memory == virtualMemory.memory);
// Check that all allocated bytes are addressable and contain expected pattern
SC_TEST_EXPECT(memcmp(memory, reference, moreThanOnePageSize) == 0);
// Now let's de-commit everything but the first page
SC_TEST_EXPECT(virtualMemory.shrink(lessThanOnePageSize));
// Address should stay stable
SC_TEST_EXPECT(memory == virtualMemory.memory);
SC_TEST_EXPECT(memcmp(memory, reference, lessThanOnePageSize) == 0);
// Decommit everything (not really needed if we're going to release() soon)
SC_TEST_EXPECT(virtualMemory.shrink(0));
SC_TEST_EXPECT(memory == virtualMemory.memory);
// Finally release (don't forget, VirtualMemory has no destructor!)
SC_TEST_EXPECT(virtualMemory.release());
SC_TEST_EXPECT(virtualMemory.memory == nullptr);

Member Function Documentation

◆ commit()

bool SC::VirtualMemory::commit ( size_t newCapacityBytes)
nodiscard

Ensures at least newCapacityBytes to be committed / accessible from the large maxCapacityInBytes block.

Parameters
newCapacityBytesIndicates how much of the reserved virtual address space that must be accessible
Note
newCapacityBytes must smaller than reservedBytes (previously reserved by VirtualMemory::reserve)

◆ getPageSize()

static size_t SC::VirtualMemory::getPageSize ( )
staticnodiscard

Obtains system memory page size.

◆ release()

bool SC::VirtualMemory::release ( )
nodiscard

Reclaims the entire virtual memory block (reserved with VirtualMemory::reserve)

◆ reserve()

bool SC::VirtualMemory::reserve ( size_t maxCapacityInBytes)
nodiscard

Reserves a large block of virtual memory of size maxCapacityInBytes.

Parameters
maxCapacityInBytesSize of the reserved amount of virtual address space
Note
The actual memory reserved will be the rounded upper multiple of VirtualMemory::getPageSize

◆ roundUpToPageSize()

static size_t SC::VirtualMemory::roundUpToPageSize ( size_t size)
staticnodiscard

Round up the passed in size to system memory page size.

◆ shrink()

bool SC::VirtualMemory::shrink ( size_t newCapacityBytes)
nodiscard

Reclaims all unused pages past newCapacityBytes (previously committed with VirtualMemory::commit)

Member Data Documentation

◆ committedBytes

size_t SC::VirtualMemory::committedBytes = 0

Current amount of committed memory.

◆ memory

void* SC::VirtualMemory::memory = nullptr

Pointer to start of reserved memory.

◆ reservedBytes

size_t SC::VirtualMemory::reservedBytes = 0

Maximum amount of reserved memory that can be committed.


The documentation for this struct was generated from the following file: