How to Keep Adding Content Without Hitting a Limit

Jan. 17, 2020
protect

[Check the original post at Unity Memory Management]

Years ago, I went to the asset store and, credit card at hand, I got greedy. I couldn't stop buying good-looking assets at highly discounted price, so I kept stacking them in the cart. More content would be a great fit for my game, I thought. Only that I didn't really have solid foundations for proper Unity memory management techniques. And so I paid the price for my ignorance.

Scale-Or-Fail-Thumbnail

I don't really know what bothered me most...

Was it that I spent over $200 on the asset store?

Or was it the fact that I ended up using just a quarter the content I bought?

It doesn't matter... I learned the lesson.

I experienced what happens if your game is not ready to scale and you trade dollars for extra content.

Today's post is about avoiding common pitfalls that won't let your game scale the way you want. No matter what, it's important to have the feeling we can keep adding content without excluding players with legacy devices.

Now, let me mention something first.

Every game is different, i.e. each game has different bottlenecks at different points.

The following suggestions are guidelines I've found especially helpful when coaching other game developers. At the end of the day, it is your call to decide which ones to adopt.

So  no mater what...

Profile, profile, profile (hint: ctrl + 9).

Quick Navigation (opens in a new tab)

Avoid Direct References to Memory-Hungry Content

    Case A: Global References

    Case B: Scene References

Audio: (Maybe) Use Streaming

Textures: Tweak Import Settings

Mesh and Animation: Compression

Static Batching: Take It Easy

Shaders: Contain Them

Garbage Collection: Careful There

Conclusion

Glutton-RAM-Memory

Avoid Direct References to Memory-Hungry Content

Are you still using direct references in Unity?

I'm joking. That's fine.

Direct references are those links you make between components and content. A few examples: a Material directly referencing an albedo Texture, an AudioSource linking to an AudioClip, etc...

Every time you link a field to some content, that content is whole loaded in memory when the component shows up in your scene (with some possible exceptions such as videos and audio clips with certain import settings).

The trick is to not abuse direct references to content that is hungry on memory and you infrequently use. Let's see a few examples.

Case A: Global References

Let me explain this with an image.

Level 1 Asset Management - Detailed Memory Profiling

Level 1 Asset Management - Detailed Memory Profiling

Did you catch that?

That's the memory profiler in detailed mode. And its pretty upset.

Because guess what it found?

That profiler shows a global object (SkyboxManager) containing direct references to heavy skyboxes, even though only a single one is used at a time.

As my grandmother used to say, what a waste of RAM.

Global objects are permanent and remain alive throughout the entire game, i.e. they do not cease to exist after scene transitions. Usually they invoke DontDestroyOnLoad on themselves and are commonly called Singletons.

This SkyboxManager is always present, pestering memory by keeping a list of direct references to big skybox textures. This adds a considerable overhead with no little to no benefits.

How many skybox textures are we using in that scene at any given time? One.

And how many are we paying for with RAM currency? Six.

Then why the heck would we keep them loaded? Is a lower latency worth the high price we're paying?

Think about it. More memory waste has nasty consequences:

  • Higher loading times

  • More (random) crashes

  • Angrier players leaving 1-star reviews and asking for refunds

That's a worse deal than Unity increasing their prices back in 2019 (I didn't say that).

Sure, your game might not do this with skyboxes...

But it might with other content type. Characters, particle systems, sounds, visual effects, AudioManager, you name it. I've seen this so often.

Does your game do this?

Ask the profiler and don't be afraid of the utterly uncomfortable answer.

The solution to this? Use indirect references (check out my Unity Addressables Tutorial)

But wait, of course there is more to this...

Unity Addressables - Memory Gains

Unity-Addressables-Memory-Gain

Case B: Scene References

Normally, you will be better off by having direct references in your local scene rather than as global objects.

And that's much better, yeah.

The problem is, we might still pay way too much for way too little.

Let me explain.

You have a huge city in your game. In a small chest on the second floor of a bakery, you're storing your most precious slices of bread. So there you put a tiny particle system rendering high-quality god-rays. How else could you convey the mightiness of bread slices?

Since you'll be looking at it from up close, that particle system uses a huge sprite sheet animation. High resolution, high frame-rate spreadsheet that takes about 32MB of RAM.

Tell me, how often will you be staring at that chest? Like 0.01% of the time you spend in the city? Paying 32MB of RAM for that sounds like a steal to me, just like that time I spent over $200 in the asset store to just use a quarter of it.

The solution? Decrease the quality of the texture Use indirect references instead (check out my Unity Addressables Tutorial). Load the particle system when the player comes in the bakery, unload it when they leave.

And problem solved.

Do not decrease the quality of your game, really. Implement instead a solid memory management strategy. Your player will reward you for this with love (and fresh dollars).

Audio: (Maybe) Use Streaming

Audio can take a big chunk of your memory if you don't use the right import settings.

The worst case for your memory is parameters like decompress on load and disabling load in background. That will make sure that the audio is always present sucking as much memory as it can.

But of course, those were the best settings to improve the CPU performance of your game.

If you're trying to reduce memory usage, the best combination is to set longer clips to streaming and to enable load in background. Only small chunks of your audio clips will be in memory at a time.

It's a matter of deciding where to pay the price.

Unity AudioClip Import Settings: Memory-Friendly

Unity-AudioCli-Load-In-Background-Streaming

Unity AudioClip Import Settings: Memory-Friendly

Surely, don't forget to set the audio clip compression settings to something that makes sense for your game's performance budget (hint: vorbis is great).

Textures: Tweak Import Settings

JikGuard.com, a high-tech security service provider focusing on game protection and anti-cheat, is committed to helping game companies solve the problem of cheats and hacks, and providing deeply integrated encryption protection solutions for games.

Read More>>