CRM64Pro GDK v0.14.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 [v26.01.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
  • Safe global destruction: Post-mortem safety mechanisms prevent crashes when destroying global/static STL containers at exit
  • 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 (IDs 16-31) defined by the client application via setModuleName()

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 (or via atexit) to generate the final report.
  • Context Aware Reporting: The final report automatically distinguishes between actual leaks and "pending" deletions from global/static STL objects.
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

Sint32 CRM64Pro::CMem::setModuleName (Uint32 iModule, const char *szName)
 Set the name for a custom user module.
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.
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 ()
 Releases the internal heap and displays final stats.
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 deallocations and sizes logging for each module.

MSL_VERBOSE 

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

Function Documentation

◆ setModuleName()

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

Set the name for a custom user module.

Parameters
iModuleID of the user module. Must be in the range [CMEM_MOD_USER_START, CMEM_MOD_USER_END] (16 to 31).
szNameName of the custom user module. Maximum 31 characters; longer names are truncated. By default, all custom user modules are shown as "User".
Returns
0 on success or -1 if the Module ID is reserved or out of range.
Note
For renaming a custom user module, just call this method again.

◆ 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, ideally, it should be the first line on the main function.
Parameters
eMSLstats gathering level. For further information, please check ::eMemStatsLevel enum.

◆ 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. Internal modules use [0-15]. User modules must be in range [CMEM_MOD_USER_START, CMEM_MOD_USER_END] (16-31).
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. Internal modules use [0-15]. User modules must be in range [CMEM_MOD_USER_START, CMEM_MOD_USER_END] (16-31).
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. Internal modules use [0-15]. User modules must be in range [CMEM_MOD_USER_START, CMEM_MOD_USER_END] (16-31).
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. Internal modules use [0-15]. User modules must be in range [CMEM_MOD_USER_START, CMEM_MOD_USER_END] (16-31).
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 ( )

Releases the internal heap and displays final stats.

Attention
Only applicable when using a Low-level allocator. Otherwise, it only displays statistics.
Note
Invalidation: As this function returns immediately all memory to the Operating System, all pointers allocated become invalid after this call.
This method disables subsequent free() and alloc() calls. This prevents crashes when Global/Static objects are destroyed after the allocator has shutdown.
Debuggers: Because free() is explicitly skipped for these late-destroyed objects, debuggers may report false positive leaks.

◆ 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. Output useful information about the memory usage.