Wwise SDK 2023.1.4
Tips to Reduce Memory Usage

It can be challenging to trim down memory usage to fit your required limit. Here are a few tips to help reduce memory usage:

Object Memory

Object memory usage is directly impacted by the number of sounds and events loaded in-memory and the amount of game objects. It contains all the properties of the objects in your project necessary to implement the behaviors of the sound design. It also contains all the game objects and their related information (game syncs values, position, orientation, and so on). The more banks are loaded, the more memory needs to be allocated. The size needed depends only on the number of sounds that can possibly be played in one scenario, level, map, game area, or the like. There are practices that can help reduce these allocations:

  • Split big SoundBanks with lots of sound structures and Events into smaller SoundBanks. For guidance, you can check the Advanced Profiler's SoundBanks tab to see in the Object Memory column how much memory each SoundBank is taking. Then you can load and unload SoundBanks dynamically as needed. Think strategically in dividing them. For example, in dividing dialog SoundBanks, avoid creating ones with all lines for a single character. Instead, group the dialog contextually.
  • Use the AK::SoundEngine::ExecuteActionOnEvent API to reduce the number of events. Play/Stop pairs can be replaced by a single Play event and a call to ExecuteActionOnEvent for the Stop and the Pause/Resume (it could be the same Play event).
  • Tightly manage your game objects. Unregister them as soon as their role is finished. Avoid keeping a pool of unused game objects alive; there is absolutely no gain in doing this, but it can cost in memory. For example, imagine an NPC dies. Unregister its game object; do not reuse it for something else. Register a brand new one when needed. As a general rule, if you have thousands of game objects alive, it is too many.
  • Do not use Actor-Mixers only to organize sounds. Folders and Work Units do not take memory, Actor-Mixers do. Unless they DO share similar properties that are not the default, then you save memory because the property is there once only. Of course, this also depends if the Actor-Mixer is referenced by events (such as SetVolume or SetPitch).
  • Try to reduce the size and complexity of large hierarchies. A common example of a large hierarchy would be an "Impact" hierarchy or a "Footstep" hierarchy. With lots of variables, it can grow large and take lots of memory for structure. Here are a few ways to reduce such a hierarchy:
    • Use RTPCs if the only thing changing in the Switch is a simple property (same samples but different volume/pitch/randomizer etc.).
    • Split your Switch Container hierarchy into multiple banks. In the SoundBank Manager, when you include a Switch container, all its sub-branches are also included. However, you can exclude some of the branches manually in the SoundBank Editor view, in the Game Sync tab or in the Edit tab. For example, in a "Footstep" hierarchy, the first Switch variable could be the Surface Type. You could then split the Switch across different SoundBanks and load them depending on the context. You could have a main "Footstep" SoundBank containing the surfaces that are encountered throughout the game, such as concrete and metal stairs in a city environment, and other contextual SoundBanks with specific surfaces, such as mud being used only in one scene/section of the game.
  • Use "external sources" to reduce the overhead of sounds that do not need as much control as offered by the Wwise Actor-Mixer hierarchy. This is usually appropriate for voice-overs.

Processing Memory

The memory in the Processing category is used to play sounds. It contains buffers to decompress, apply effects, and mix the audio sources. It is directly influenced by the number of sounds playing at the same time. It is also influenced by the number and type of effects that are used at the same time. To trim this down, you need to ask yourself how many sounds you want to hear at the same time. Some games will rarely have a scenario where more than 10 sounds are heard, others will have hundreds. You need to consider your worst case.

As a guideline, we have done some profiling on some games (on Xbox One) and had the following numbers:

  • 1 MB will let you play approximately 42 voices
  • 2 MB will let you play approximately 96 voices Although it scales mostly linearly, it really depends on which codec is used, how many effects, and other such factors. For example, using the Vorbis codec will use around 50% more memory per voice depending on the quality settings. Imagine 170 sounds at the same time: it is probably unintelligible and, therefore, useless. However, it takes some experimentation to find an ideal real number of voices for your game. Use the Memory tab of the profiler, profile multiple scenarios in your game, and note how much is used in resources.

To reduce the memory used for processing, you need to reduce the number of simultaneous voices. This can be done using:

  • Playback Limits (Advanced Settings). For example, do you really need to hear 50 bullet ricochets? If not, maybe limit those sounds to say 15.
    Note: You can set limits on busses as well.
  • Priority (Advanced Settings). For example, bullets could be less important than dialog. This means that bullets would get kicked first if there are too many sounds. Use in conjunction with Playback Limits.
  • Distance-based priority offset (Advanced Settings). Objects that are far are usually less important than closer ones. For example, again with bullets, we don't need to hear bullets that are 10 meters away if there are 15 other bullets sounds closer than that.
  • Below Threshold Behavior (Advanced Settings). The least expensive option (CPU and memory) is "Kill Voice", which is useful for non-looping sounds. The second preferred option is "Send To Virtual" "Play from beginning", then "Send To Virtual" "Resume" and then "Send To Virtual" "Play from elapsed time". "Continue to play" and "Play from elapsed time" are the most costly options, and Wwise's default value is "Continue To Play".
  • Volume Threshold (Project Settings). This will help kill the sounds too faint to be heard. This goes hand in hand with the Below Threshold Behavior and also the Attenuation settings (farther usually means fainter).
    Note: You can change the volume threshold programmatically at run-time. You may use this in game locations that are more process-heavy in order to send more voices to their "under volume threshold" state.
  • A change to the used codec settings (Conversion Settings). Vorbis needs extra memory to decompress audio. Different parameters can increase or reduce the amount needed. However, think carefully about the tradeoff: using a different codec or a weaker compression ratio will relieve the Processing memory load but at the cost of larger files in memory, if they're in loaded banks. In some cases it's better to see an extra 500 KB in Processing memory usage to save a few MBs on Media memory and, therefore, on the overall audio budget.
  • Fewer or lower quality. Some effects need a lot of memory to be processed. One very common memory consumer is the Reverb effect, in any of its available flavors. Realistically, your game should have very few reverbs running concurrently. As a rule, we suggest less than 4. Also, reducing the quality or length of the reverb will help.

Media Memory (SoundBanks)

The amount of memory taken by SoundBanks is mostly dictated by the sound data in it. Controlling the amount of memory used by your media can be done through:

  • Splitting big SoundBanks with lots of sound structures and Events into smaller SoundBanks. Load and unload dynamically as needed.
  • Streaming more sounds from disk (Sounds' properties). Sounds that are latency-sensitive can use prefetch media, which can be pre-loaded, or be streamed into cache on-demand using the PinEventInStreamCache API.
  • Using the PrepareEvent() API.
  • Compressing the audio more (Conversion Settings, codec, and so on).
  • Using a lower sampling rate. Also look at the Automatic Sample Rate Detection feature of the Conversion Settings.
  • Replacing wind-type sounds with a Soundseed Wind/Woosh plug-in equivalent. Wind ambiance tends to be long loops, which can take a lot of media space. Blades woosh, propellers, wind rushing in a car with open windows, ventilation noises, and so on can be modelled with this plug-in. Also consider non-windy applications: any noisy sound could be modeled. Examples: Ocean waves or the sound of a highway in the distance.

Tuning "Temp Alloc" Memory

Wwise uses an internal pool of memory to manage some temporary allocations that persist for less than one audio-render tick, which are represented in the Advanced Profiler's Memory tab as "Temp Alloc". These temporary allocations exist for a specific amount of time, have very little overhead, are handled internally by the sound engine, and cannot be forwarded to developer-provided memory allocation hooks. Instead, the only allocations in this regard that are observed by the Advanced Profiler and memory allocation hooks are the larger memory blocks that the temporary allocations are made from. Therefore, it might be desirable to manually tune the management of "Temp Alloc" memory blocks, in order to better optimize memory usage in your game.

During AK::MemoryMgr::Init, AkMemSettings::tempAllocSettings controls the behavior of the memory blocks for each Temp Alloc category. Notably, this includes configuring the size of the memory blocks, the minimum number of blocks that the system keeps allocated at all times, and how many blocks have to be unused for a tick before the system starts freeing memory. You can use AK::GetTempAllocStats() to see how much memory the Temp Alloc system uses in your game at runtime, and better fine tune configuration of the system.

The following are some suggestions depending on your game's requirements, or other behavior observed during profiling:

  • If you are not concerned about the overhead of allocating and freeing the memory blocks, or the memory fragmentation that is incurred when the memory blocks are freed, it might be desirable to set AK::TempAllocInitSettings::uMinimumBlockSize to a lower value than the default, so that it better matches the memory usage of your game's needs at any given time.
  • If the allocation and freeing of blocks causes excessive memory fragmentation, you can measure AK::TempAllocStats::uPeakMemUsed to view the Temp Alloc system's peak memory usage, and then ensure that the AK::TempAllocInitSettings::uMinimumBlockCount is set to a high enough value so that all of the blocks you might use are allocated when the sound engine is initialized, and never freed afterward.
  • If you want to avoid freeing memory blocks without evaluating your peak memory usage, you can set AK::TempAllocInitSettings::uMaximumUnusedBlocks to a high value to ensure that the system can allocate new blocks, but not free them, even during periods of low memory load.
  • If you are using the Job Manager for audio rendering, as described in Leveraging the Job Manager for Concurrent Execution of Audio Rendering Jobs, the number of memory blocks will increase. This is because the memory blocks are all thread-local, and one memory block is typically allocated by each active worker. It might be desirable to lower AK::TempAllocInitSettings::uMinimumBlockSize so that using more workers does not cause a significant increase in used memory in your game.
  • If your memory allocation system includes some metadata adjacent to large memory allocations, it might be worth ensuring that the amount of memory allocated by the memory blocks does not cause a significant amount of waste. Given a requested allocation of 2048 KiB, some memory allocation systems might actually map 2112 KiB of memory. However, a requested allocation might of 2047 KiB would map 2048 KiB of memory. The block sizes do not need to be powers of two, or exactly matched to page sizes, so it might be preferable to set AK::TempAllocInitSettings::uMinimumBlockSize to a slightly reduced value than intended in order to mitigate waste in this regard.

Some debugging options are available in AK::TempAllocInitSettings. In the Debug and Profile configuration of the sound engine, AK::TempAllocInitSettings::bDebugDetailedStats and AK::TempAllocInitSettings::bDebugEnableSentinels are enabled by default in order to improve tracking of usage statistics, and to provide some easy detection of buffer overruns. Disable these options when the highest performance, or most accurate profiling data, is required for your application. Support for these options is removed entirely in the Release configuration of the sound engine.

Tuning "Span Count"

If your Memory Manager integration relies on Wwise's integration of rpmalloc, it might be desirable to adjust AK::MemSettings::uVMSpanCount and AK::MemSettings::uDeviceSpanCount in order to reduce the amount of memory reserved by the system. There are three options available for these settings, which provide different trade-offs for CPU and Memory use: AkSpanCount_Small, AkSpanCount_Medium, and AkSpanCount_Huge.

AkSpanCount_Huge is the default value, which offers the best CPU performance by reducing the number of calls made to AkMemSettings::pfAllocVM, but also because in supported integrations, and on some platforms, memory mappings can be made using 2MiB pages, instead of 4KiB or 16KiB pages. Utilization of 2MiB pages can reduce the number of translation lookaside buffer (TLB) misses during sound engine execution, and help improve overall CPU performance.

AkSpanCount_Small adjusts the amount of memory requested at any given time to be as low as 64KiB. This can reduce the amount of memory reserved by Wwise, but can increase the amount of CPU usage due to an increase in calls to AkMemSettings::pfAllocVM. Depending on your implementation of the AkMemSettings::pfAllocVM callback, this might also prevent the usage of 2MiB pages for memory mappings.

AkSpanCount_Medium balances memory and CPU usage, by requesting memory blocks as low as 512KiB. This can reduce the number of calls to AkMemSettings::pfAllocVM compared to AkSpanCount_Small, but still might prevent the usage of 2MiB pages for memory mappings.

Note: If your implementation of AkMemSettings::pfAllocVM provides blocks of pre-mapped memory, and rarely invokes a system call for a new memory mapping, we strongly recommend that you use a setting of AkSpanCount_Small because the relative cost of calls to AkMemSettings::pfAllocVM should be greatly reduced, and your pre-mapped memory might already be using 2MiB pages.

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