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

 VirtualMemory (const VirtualMemory &)=delete
 
 VirtualMemory (VirtualMemory &&)=delete
 
VirtualMemoryoperator= (const VirtualMemory &)=delete
 
VirtualMemoryoperator= (VirtualMemory &&)=delete
 
bool reserve (size_t maxCapacityInBytes)
 Reserves a large block of virtual memory of size maxCapacityInBytes.
 
void release ()
 Reclaims the entire virtual memory block (reserved with VirtualMemory::reserve)
 
bool commit (size_t sizeInBytes)
 Ensures at least sizeInBytes to be committed / accessible from the large maxCapacityInBytes block.
 
bool shrink (size_t sizeInBytes)
 Reclaims all unused pages past sizeInBytes (previously committed with VirtualMemory::commit)
 
size_t size () const
 Returns how many bytes are currently committed / accessible.
 
size_t capacity () const
 Returns how many bytes are currently reserved.
 
void * data ()
 Returns a pointer to the start of the reserved virtual memory.
 
const void * data () const
 Returns a pointer to the start of the reserved virtual memory.
 

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.
 

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.data());
// 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.data());
// 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.data());
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.data());
// Finally release (don't forget, VirtualMemory has no destructor!)
virtualMemory.release();
SC_TEST_EXPECT(virtualMemory.data() == nullptr);

Member Function Documentation

◆ capacity()

size_t SC::VirtualMemory::capacity ( ) const
inlinenodiscard

Returns how many bytes are currently reserved.

◆ commit()

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

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

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

◆ data() [1/2]

void * SC::VirtualMemory::data ( )
inlinenodiscard

Returns a pointer to the start of the reserved virtual memory.

◆ data() [2/2]

const void * SC::VirtualMemory::data ( ) const
inlinenodiscard

Returns a pointer to the start of the reserved virtual memory.

◆ getPageSize()

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

Obtains system memory page size.

◆ release()

void SC::VirtualMemory::release ( )

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 sizeInBytes)
nodiscard

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

◆ size()

size_t SC::VirtualMemory::size ( ) const
inlinenodiscard

Returns how many bytes are currently committed / accessible.


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