Version

menu_open
Warning: you were redirected to the latest documentation corresponding to your major release ( 2024.1.1.8691 ). Should you wish to access your specific version's documentation, please download the offline documentation from the Audiokinetic Launcher and check the Offline Documentation option in Wwise Authoring.
Wwise SDK 2024.1.1
Configuration and Tuning of AkMemoryArenas

AkMemoryArena is a custom memory allocator used by the Wwise sound engine. It has a variety of settings you can use to manage the memory it reserves. Multiple AkMemoryArenas are used by the sound engine, and proper tuning of them to suit your project’s requirements can provide significant improvements to the overall memory reservation of the sound engine.

Overview of AkMemoryArena

AkMemoryArena acts as a general-purpose memory allocator, with all memory allocations put into one of four separate heaps based on their size: Small, Medium, Large, or Huge.

Small allocations are any allocation that is 256 bytes or smaller. This threshold is not configurable. These are managed in a “Small-block allocator” (“SBA”) heap. The SBA manages all allocations in spans consisting of fixed-sized blocks of memory, which allows for consistent behavior with regards to memory fragmentation. Each span is of a configurable size, and these spans are allocated from the parent Medium or Large heap. The SBA is initialized with an initial region of memory, which reduces the amount of overhead used for allocations in the SBA heap. Normally, memory allocations in the AkMemoryArena, across all size classes, require 16 bytes of overhead, which is used for allocation metadata. However, SBA allocations inside the initial region do not require any such overhead. For example, if a normal SBA span is 16 kibibytes in size, and has been configured to handle allocations that are 64 bytes in size, then the span can handle approximately 200 blocks of memory, each 80 bytes in size. However, if the same 16 kibibyte span is allocated inside the initial region, it can handle approximately 250 blocks of memory, each 64 bytes in size.

Medium and Large allocations are larger than 256 bytes in size, but smaller than the value of AkMemoryArenaSettings::uAllocSizeLarge or AkMemoryArenaSettings::uAllocSizeHuge. The heaps used for the Medium and Large allocations use an algorithm based on the Two-Level Segregated Fit (“TLSF”) algorithm. As a result, these heaps are able to offer allocations and frees with O(1) performance. These heaps use a good-fit memory allocation policy to determine where allocations should be placed. However, unlike the original TLSF algorithm, the TLSF heap used by the AkMemoryArena also allows new spans of memory to be requested over time as memory needs increase, without requiring the new memory span to be contiguous with other spans of memory. The TLSF heap also releases the memory when all constituent allocations have been freed. When Medium or Large allocations are requested, the TLSF heap first attempts to find a free block of memory in the initial Base span of memory, and if a free block is not available, it then attempts to find a free block of memory among the already mapped Medium or Large spans. If a free block is still not available, then a request for a new span in the Huge allocation heap is made and added to the list of Medium or Large spans. Similarly, when a span no longer has any allocations, it is considered “Unused”. After a certain number of spans are unused, they are released to the system.

Huge allocations are any allocation that is too large to fit in the Medium or Large heaps. These allocations are placed in separate spans and do not share memory with other allocations. In addition, memory for Huge spans is never reused or cached over time, that is, once the constituent memory allocation is freed, the span is released immediately.

AkMemoryArenaSettings

The initialization settings of the AkMemoryMgr include an array of settings that allow you to configure the different AkMemoryArenas used by the sound engine. Unless noted, none of the sizes described below need to be a power of two.

  • AkMemoryArenaSettings::bEnableSba - Controls whether or not the SBA should be activated. If inactive, then every Small allocation is considered a Medium allocation and sent to the TLSF heap. By default, this option is disabled for the Media AkMemoryArena because Media allocations are typically too large for the SBA.
  • AkMemoryArenaSettings::uSbaInitSize - The size, in bytes, of the initial region of memory for the SBA heap. Allocations in this initial region take up less space due to the lack of memory allocation overhead.
  • AkMemoryArenaSettings::uSbaSpanSize - The size, in bytes, of each span of memory used for the SBA heap. Higher values can slightly improve system performance but can result in greater memory waste due to memory being left unused. Note that this value must be a power of two.
  • AkMemoryArenaSettings::uSbaMaximumUnusedSpans - The number of SBA spans that will be left in an unused state before being freed when allocated outside of the initial region of memory for the SBA heap.
  • AkMemoryArenaSettings::uTlsfInitSize - The size, in bytes, of the initial Base span of memory used for the TLSF heap.
  • AkMemoryArenaSettings::uTlsfSpanSize - The size, in bytes, of each secondary span of memory created for Medium allocations. If an allocation request, which requires a new span, is larger than this size, then the size of the span rounds up the size of the allocation request to the next multiple of this value.
  • AkMemoryArenaSettings::uTlsfLargeSpanSize - The size, in bytes, of each secondary span of memory created for Large allocations. If an allocation request, which requires a new span, is larger than this size, then the size of the span rounds up the size of the allocation request to the next multiple of this value.
  • AkMemoryArenaSettings::uTlsfSpanOverhead - When requesting a new span for TLSF, this is the number of bytes that is subtracted from the Huge allocation that is requested.
  • AkMemoryArenaSettings::uTlsfMaximumUnusedMediumSpans - The number of spans for Medium allocations that can be empty and unused before being released.
  • AkMemoryArenaSettings::uTlsfMaximumUnusedLargeSpans - The number of spans for Large allocations that can be empty and unused before being released.
  • AkMemoryArenaSettings::uAllocSizeLarge - The minimum size, in bytes, that an allocation must be in order to be classified as Large. All allocation sizes smaller than this value, but larger than 256 bytes, are considered Medium allocations. Note that if this value is greater than uAllocSizeHuge, no allocations will be classified as Large.
  • AkMemoryArenaSettings::uAllocSizeHuge - The minimum size, in bytes, that an allocation must be in order to be classified as Huge.
  • AkMemoryArenaSettings::uMemReservedLimit - The maximum amount of memory, in bytes, that can be reserved by this AkMemoryArena. If the Huge heap attempts to request memory beyond this limit, a nullptr is returned, and fnMemAllocSpan is not called.
  • AkMemoryArenaSettings::fnMemAllocSpan: - The user-provided callback executed when the Huge heap requires a new allocation, including any requests for new spans from the TLSF heap.
  • AkMemoryArenaSettings::fnMemFreeSpan - The user-provided callback executed when the Huge heap frees an allocation, including releasing any spans from the TLSF heap.

The following code sample can be used for the default initialization of the AkMemoryArenaSettings for the AkMemoryMgr, and might be a good starting point for further customization of the AkMemoryArenaSettings:

AkMemSettings memSettings;
for (AkUInt32 eArenaType = AkMemoryMgrArena_Primary; eArenaType < AkMemoryMgrArena_NUM; eArenaType++)
{
AK::MemoryArena::AkMemoryArenaSettings& arenaSettings = memSettings.memoryArenaSettings[eArenaType];
// Set defaults for all of the settings
arenaSettings.bEnableSba = true;
arenaSettings.uSbaInitSize = 0;
arenaSettings.uSbaSpanSize = 16384;
arenaSettings.uSbaMaximumUnusedSpans = 1;
arenaSettings.uTlsfInitSize = 2 * 1024 * 1024;
arenaSettings.uTlsfSpanSize = 2 * 1024 * 1024;
arenaSettings.uTlsfLargeSpanSize = 8 * 1024 * 1024;
arenaSettings.uTlsfSpanOverhead = 128; // std::malloc in particular appears to generate 128B of overhead for our large allocations
arenaSettings.uTlsfMaximumUnusedMediumSpans = 1;
arenaSettings.uTlsfMaximumUnusedLargeSpans = 1;
arenaSettings.uAllocSizeLarge = UINT_MAX;
arenaSettings.uAllocSizeHuge = 4 * 1024 * 1024;
arenaSettings.uMemReservedLimit = 0;
}
// ... except...
// The primary heap should be initialized with a larger uTlsfInitSize and uSbaInitSize,
// since almost every project will have a lot of data going into them
// The media heap should not have an SBA at all
// the "profiler" arena should not be initialized at all if we're in "optimized" (ie release) configs
#if defined(AK_OPTIMIZED)
#endif

AkMemoryArenaSettings Allocation Callbacks

For AkMemoryArenaSettings::fnMemAllocSpan and AkMemoryArenaSettings::fnMemFreeSpan, the callbacks have the following requirements and behavior:

  • fnMemAllocSpan only needs to return a pointer to a memory allocation of the requested size. The returned allocation has no requirements concerning the alignment of the returned memory, nor does it need to be contiguous with other prior memory allocations.
  • fnMemFreeSpan only needs to release the memory at the address given.
  • fnMemFreeSpan is only called with addresses previously returned via fnMemAllocSpan. The size parameter is also the same value with which the allocation was initially requested.
  • During execution of fnMemAllocSpan, an arbitrary value can be written to out_userData. This value is provided to the equivalent call to fnMemFreeSpan, as the in_userData parameter.

The callbacks can be very flexible in their implementations. Even the following can be used, for example:

void* AllocSpan(size_t size, size_t* out_userData)
{
return std::malloc(size);
}
void FreeSpan(void* address, size_t size, size_t in_userData)
{
std::free(address);
}

The Memory Arenas tab in the Advanced Profiler lists every currently allocated span, with the address and userData values for each span matching the values returned from these callbacks. This can be useful for debugging purposes, especially when used alongside other debugging and profiling tools.

Recommendations for AkMemoryArena Configuration

The default settings for the AkMemoryArenas managed by the AkMemoryMgr are tuned such that they keep initial memory reservation low and some other major pitfalls are avoided. However, tuning many of these settings is recommended to suit your project’s needs. Intelligent tuning can result in significant optimizations to memory reservation in Wwise, overall memory reservation by the game engine, and CPU performance in Wwise. The following are some suggestions to experiment with, or consider, in order to find what works best for your project:

  • Set AkMemoryArenaSettings::uTlsfInitSize for the Primary and Media arenas to match typical memory usage or total memory budgets. Typically, a larger Base span results in better memory fragmentation for the TLSF algorithm. Attempting to use a single span can also allow you to monitor when memory budgets are exceeded by checking when a request for any secondary memory spans is made. It can also help with application-wide budgeting of memory, because the total system memory reservation at startup will better reflect the total system memory reservation after an extended period of play.
  • Set AkMemoryArenaSettings::uSbaInitSize for the Primary AkMemoryArena to match typical SBA reservation requirements during gameplay. Using the Memory Arenas tab in the Advanced Profiler, measure the SBA Reserved requirements during typical gameplay, or find a specific high watermark, and set uSbaInitSize to match that target. Setting this to a larger value means that more SBA memory allocations will be placed in the initial region of memory and will benefit from the lack of overhead for individual memory allocations. This can also reduce long-term fragmentation in the Primary TLSF heap by reducing the number of SBA spans that are allocated in the TLSF heap.
  • Alternatively: Set AkMemoryArenaSettings::uTlsfInitSize to a lower value to reclaim memory for other systems. If you have gameplay scenarios that can cleanly release a significant amount of memory, with few lingering effects from memory fragmentation, it might be preferable to lower uTlsfInitSize of the Primary or Media arenas so that the memory can be used by other systems.
  • Alternatively: Set a larger value of AkMemoryArenaSettings::uTlsfMaximumUnusedMediumSpans to find the memory reservation watermark. By default, uTlsfMaximumUnusedMediumSpans and uTlsfMaximumUnusedLargeSpans is set to 1 in order to readily reclaim unused memory. Temporarily setting this to a higher value, so that spans are allocated and never released, can help you identify your memory reservation watermark.
  • Use Large memory allocations to mitigate fragmentation. By default, Large memory allocations are disabled, but in some situations, it might be desirable to keep allocations of a certain size physically separated from each other to mitigate long-term system fragmentation. Some experimentation to find appropriate values for uAllocSizeLarge and uTlsfLargeSpanSize might be worthwhile. This might increase overall memory reservation early on due to memory being left unused across more spans, but it can result in lower memory fragmentation over time. Note that Medium and Large allocations are both allocated in the Base span if there is space available.
  • Lower AkMemoryArenaSettings::uAllocSizeHuge to reduce internal fragmentation. Because Huge allocations are considered to be standalone, they are not affected by internal memory fragmentation. If the extra CPU cost and external fragmentation due to more frequent calls to fnMemAllocSpan and fnMemFreeSpan can be managed, it might be desirable to lower the threshold of what are considered Huge allocations to direct more memory to that category.
  • Set AkMemoryArenaSettings::uTlsfSpanOverhead to match the size of the allocation metadata from your fnMemAllocSpan implementation. If your implementation of fnMemAllocSpan creates a memory allocation that itself requires some metadata, measure the size of that metadata, and increase uTlsfSpanOverhead to match that size. This value is used to slightly reduce the requested size of any TLSF span, which can help ensure that fnMemAllocSpan’s allocation maps the intended amount of memory. For example, a TLSF span size that is supposed to be 2.00MiB (2097152 bytes) might result in the actual mapped memory being 2.02MiB in size (2113536 bytes) due to needing an additional page of memory for the memory allocation metadata. However, if it is expected that there is 128 bytes of metadata required, then uTlsfSpanOverhead can be set to that value to subtract that amount from the requested TLSF span size. In this example, the requested TLSF span size will be 2097024 bytes, and would result in exactly 2.00MiB of memory being mapped, thereby reducing the amount of wasted physical memory.
AK::MemoryArena::AkMemoryArenaSettings memoryArenaSettings[AkMemoryMgrArena_NUM]
Configuration of memory arenas for default memory allocator. For more information,...
@ AkMemoryMgrArena_Primary
@ AkMemoryMgrArena_Profiler
AkForceInline void FreeSpan(void *address, size_t size, size_t in_userData)
@ AkMemoryMgrArena_NUM
@ AkMemoryMgrArena_Media
uint32_t AkUInt32
Unsigned 32-bit integer.
AkForceInline void * AllocSpan(size_t size, size_t *out_userData)

Was this page helpful?

Need Support?

Questions? Problems? Need more info? Contact us, and we can help!

Visit our Support page

Tell us about your project. We're here to help.

Register your project and we'll help you get started with no strings attached!

Get started with Wwise