CRM64Pro GDK v0.13.0
A free cross-platform game development kit built on top of SDL 3.0
Loading...
Searching...
No Matches
Memory Manager

Description

High-performance and thread-safe memory allocation system [v25.12.0].

Overview

The Memory Manager (CMem) provides high-performance, thread-safe functions for allocating memory blocks while helping to reduce memory fragmentation. All CRM64Pro GDK modules and external libraries (SDL3, libpng, etc.) use CMem for memory allocation and deallocation.
Client applications can also use CMem and define different module numbers for precise and specific statistics tracking.

CMem functional layers

Key features

  • High performance: Optimized memory allocation with optional low-level allocators
  • Thread-safe: All allocation functions are safe for concurrent access
  • Unified Logging: Seamless integration with the Core Log system to prevent file locking issues
  • Reduced fragmentation: Memory pooling strategies minimize heap fragmentation
  • Per-module statistics: Track memory usage across GDK modules, libraries and custom modules
  • Verbose profiling: CSV export of allocation histograms and memory evolution over time

Functional layers

CMem is composed of three different functional layers:

FrontendUser-facing API: alloc(), calloc(), realloc(), alloc_aligned(), free(), free_aligned(), setLogLevel(), setVerboseSampleInterval(), info() and destroy()
Stats systemPer-module memory tracking, CSV profiling, and logging bridge
Low-level allocatorPluggable backend allocator (Standard C/C++ or ltalloc)

Logging Integration

CMem utilizes a Single Pipe Architecture for outputting statistics:

  • Active Mode: When the GDK is running, CMem routes all output through the Log Manager. This ensures thread safety and prevents file handle contention (e.g., when the log file is kept open for performance).
  • Fallback Mode: If the Log Manager is destroyed before CMem (e.g., calling CMem::destroy() at the very end of main()), CMem automatically falls back to the last known log configuration (File/Console) to ensure final leak reports are not lost.

Tracked modules

The stats system provides memory information for each of the following modules:

CRM64ProInterfaces, managers, objects, STL containers and network system
Core librariesSDL3, TinyXML2 and zlib-ng
Audio librarieslibxmp, dr-flac, dr-mp3 and stb-vorbis
Image librarieslibpng
User modulesCustom modules defined by the client application

Verbose profiling

In ::MSL_VERBOSE mode, two CSV files are produced:

Allocation histogramDistribution of all allocation sizes grouped by module
Memory evolutionTime-series snapshots of memory allocation per module (default interval: 0.5 seconds, configurable via setVerboseSampleInterval())

Low-level allocators

Two allocator backends are available. The selection affects how exact memory usage is tracked on different platforms:

Standard C/C++Default system allocator.
Windows: Uses _msize for exact tracking.
Linux: Uses malloc_usable_size.
macOS: Uses malloc_size.
ltallocModified high-performance allocator. Cross-platform exact tracking via ltmsize. Thread-safe with some memory overhead (see details below)


ltalloc details
The ltalloc allocator requests memory from the operating system in 1MB blocks and automatically creates memory pools for common allocation sizes:

  • Pool sizes: 16B, 32B, 64B, 128B, 256B, 512B, 1KB, 2KB, 4KB, 8KB, 16KB, 32KB, 64KB, 128KB, 256KB and 512KB
  • Large allocations: Requests greater than 512KB trigger a direct system call
  • Overhead considerations: A single 16B allocation reserves 1MB from the OS. Requests are rounded up to the nearest power-of-two pool size (e.g., 200B uses a 256B slot, wasting 56B)

Best practices

  • Call setLogLevel() before any other CMem function in your main() to capture all allocation information
  • The stats gathering level can be modified at any point, but info() will dump based on the current active mode
  • Call destroy() at the very end of your application, right before the final return statement, to verify zero leaks
  • Alternatively, use atexit(CMem::destroy) for automatic cleanup
  • When converting CRM64Pro STL containers to standard STL, use explicit conversions (e.g., std::string sDest = sSource.c_str();)
Note
CRM64Pro STL containers use the CMem allocator and are not directly compatible with standard STL containers. Explicit conversions are required:
CRM64Pro::string sSource = "mySourceValue";
std::string sDest = sSource; // Will fail
std::string sDest = sSource.c_str(); // OK
Warning
The new/delete global operators are not overridden by default. However, you can enable this behavior by defining C64_OVERRIDE_NEW before including the headers and compiling CRM64Pro GDK. If enabled, all C++ allocations will be tracked by CMem.

Enumerations

enum  CRM64Pro::CMem::eMemStatsLevel { CRM64Pro::CMem::MSL_NULL = 0 , CRM64Pro::CMem::MSL_NORMAL = 2 , CRM64Pro::CMem::MSL_HIGH = 4 , CRM64Pro::CMem::MSL_VERBOSE = 8 }
 Memory statistics verbosity. More...

Functions

void CRM64Pro::CMem::setVerboseSampleInterval (Sint32 iInterval)
 Set time interval between each sample when the stats level is ::MSL_VERBOSE. By default it is set to 500ms.
void CRM64Pro::CMem::setLogLevel (eMemStatsLevel eMSL)
 Set the memory stats gathering level.
Sint32 CRM64Pro::CMem::setModuleName (Uint32 iModule, const char *szName)
 Set the memory log mode.
void * CRM64Pro::CMem::alloc (size_t iSize, Uint32 iModule)
 Reserve a memory block using C64 Memory Manager.
void * CRM64Pro::CMem::calloc (size_t iNum, size_t iSize, Uint32 iModule)
 Reserve a memory block using C64 Memory Manager and reset it to 0.
void * CRM64Pro::CMem::realloc (void *pMem, size_t iSize, Uint32 iModule)
 Reallocate a memory block using C64 Memory Manager.
void * CRM64Pro::CMem::alloc_aligned (size_t iSize, size_t iAlign, Uint32 iModule)
 Reserve a memory block using C64 Memory Manager aligned to the desired value.
void CRM64Pro::CMem::free (void *pMem)
 Deallocate a memory block using C64 Memory Manager.
void CRM64Pro::CMem::free_aligned (void *pMem)
 Deallocate a memory block using C64 Memory Manager.
void CRM64Pro::CMem::destroy ()
 Destroy all internal memory used by the Low-Level Allocator.
Sint32 CRM64Pro::CMem::info (Sint32 iMode)
 Output useful information about the memory usage.

Enumeration Type Documentation

◆ eMemStatsLevel

Memory statistics verbosity.

Enumerator
MSL_NULL 

Disable memory statistics gathering. Default for release builds.

MSL_NORMAL 

Collect allocations per module (CRM64Pro and user). Default for debug builds.

MSL_HIGH 

::MSL_NORMAL plus deallocation logging for each module.

MSL_VERBOSE 

::MSL_HIGH plus: memory growth per module (CMem-Evolution.csv) and request size histogram per module (CMem-Histogram.csv).

Function Documentation

◆ setVerboseSampleInterval()

HandleDLL void CRM64Pro::CMem::setVerboseSampleInterval ( Sint32 iInterval)

Set time interval between each sample when the stats level is ::MSL_VERBOSE. By default it is set to 500ms.

Parameters
iIntervalinteger with time in milliseconds [1, 30000].

◆ setLogLevel()

HandleDLL void CRM64Pro::CMem::setLogLevel ( eMemStatsLevel eMSL)

Set the memory stats gathering level.

Note
The memory stats level must be set before any other call to CRM64Pro (including custom STL containers), ideally, it should be the first line on the main function.
Parameters
eMSLstats gathering level. For further information, please check ::eMemStatsLevel enum.

◆ setModuleName()

HandleDLL Sint32 CRM64Pro::CMem::setModuleName ( Uint32 iModule,
const char * szName )

Set the memory log mode.

Parameters
iModuleused for storing who requested the memory for statistics results. Only for custom user modules.
szNamename of the custom user module. By default, all custom user modules are shown as "User".
Returns
0 on success or a negative error code on failure.
Note
For renaming a custom user module, just call this method again.

◆ alloc()

HandleDLL void * CRM64Pro::CMem::alloc ( size_t iSize,
Uint32 iModule )

Reserve a memory block using C64 Memory Manager.

It is automatically aligned to 4 in 32bits mode and 16 for 64 bits mode.

Parameters
iSizesize of the memory block, in bytes.
iModuleused for storing who requested the memory for statistics results.
Returns
A pointer to the reserved memory block.
Note
It is a replacement of standard malloc() function.

◆ calloc()

HandleDLL void * CRM64Pro::CMem::calloc ( size_t iNum,
size_t iSize,
Uint32 iModule )

Reserve a memory block using C64 Memory Manager and reset it to 0.

It is automatically aligned to 4 in 32bits mode and 16 for 64 bits mode.

Parameters
iNumnumber of elements to allocate.
iSizesize of each element.
iModuleused for storing who requested the memory for statistics results.
Returns
A pointer to the reserved memory block.
Note
It is a replacement of standard calloc() function.

◆ realloc()

HandleDLL void * CRM64Pro::CMem::realloc ( void * pMem,
size_t iSize,
Uint32 iModule )

Reallocate a memory block using C64 Memory Manager.

It is automatically aligned to 4 in 32bits mode and 16 for 64 bits mode.

Parameters
pMempointer to the memory area to be reallocated.
iSizesize of the memory block, in bytes.
iModuleused for storing who requested the memory for statistics results.
Returns
A pointer to the reserved memory block.
Note
It is a replacement of standard realloc() function.

◆ alloc_aligned()

HandleDLL void * CRM64Pro::CMem::alloc_aligned ( size_t iSize,
size_t iAlign,
Uint32 iModule )

Reserve a memory block using C64 Memory Manager aligned to the desired value.

Parameters
iSizesize of the memory block, in bytes.
iAlignspecifies the alignment. Must be a valid alignment supported by the implementation. Usually a 2^n number is supported.
iModuleused for storing who requested the memory for statistics results.
Returns
A pointer to the reserved memory block.
Note
It is a replacement of standard aligned_alloc() function.

◆ free()

HandleDLL void CRM64Pro::CMem::free ( void * pMem)

Deallocate a memory block using C64 Memory Manager.

Parameters
pMempointer to a memory block previously allocated with alloc(), calloc() or realloc().
Note
It is a replacement of standard free() function.

◆ free_aligned()

HandleDLL void CRM64Pro::CMem::free_aligned ( void * pMem)

Deallocate a memory block using C64 Memory Manager.

Parameters
pMempointer to a memory block previously allocated with alloc_aligned().
Note
It is a replacement of standard free() function.

◆ destroy()

HandleDLL void CRM64Pro::CMem::destroy ( )

Destroy all internal memory used by the Low-Level Allocator.

Only applicable when using a Low-Level Allocator. It also call info() for displaying memory stats.

Warning
Use it carefully as all allocations will be invalid after calling this method. It can be safely called at the very end of your application although if there is any STL container statically constructed, an error will happen. For these cases you can either reduce the scope of the STL container or use atexit() function.
Note
Modern operating systems will free and destroy all assigned memory once the application exists but a memory debugger will detect the leak.

◆ info()

HandleDLL Sint32 CRM64Pro::CMem::info ( Sint32 iMode)

Output useful information about the memory usage.

Parameters
iMode1 for displaying extra information about the Low-Level Allocator (default value) or 0 for disabling it.
Returns
0 on success or a negative error code on failure.
Note
The output of this function uses the mode set by the default log (LM_NULL, LM_STDOUT, LM_FILE, LM_FILEAPPEND or LM_CONSOLE) and depends on the eMemStatsLevel level set.