A Story of NullReferenceException [Part 2]

This is a story of NullReferenceException part 2. If you haven’t read the part one, you can still do it here.

Don’t trust GetComponent()

GetComponent() is a commonly used function to access current GameObject’s component. Here’s a code snippet showing how to disable object’s renderer, so it is no longer visible in the game view.

Of course GetComponent() will return null if current object doesn’t have the requested component.  That is a serious risk, because components can be easily removed by the designer at any time without any warning.

Use [RequireComponent]

First you should use [RequireComponent] annotation whenever it is possible.

Note that [RequireComponent] will not guarantee that given component is always available. What it actually does, is adding missing component during object setup. Nothing fancy, but it lowers the risk of NullReferenceException a little.

Decide what to do on failure

Yes, you definitely should do a null check. But you have to decide what you want to do if the component happens to be missing. You have three options in general.

  1. Display an error and ignore.
  2. Report the incident as bug.
  3. Try to recover.

As you can see there’s no option for throwing an exception. That’s because we want our game to be as stable as possible.

1. Display an error and ignore

This is the easiest way to handle these kind of bugs. If you encounter them when working in Unity Editor then you will have a good opportunity to fix it before it is even released. Yet your situation will not be that comfortable if this issue appears on your player’s devices that usually you don’t have direct access to.

Please note that on line 7 I wrote if (renderer) instead of if (renderer != null). That’s because the UnityEngine.Object is overriding the (bool) operator and under the hood this is a nice shortcut to do a null check.

2. Report incident as bug

If you have the opportunity, you may want to report this incident as a bug. Automatic bug reporting helps you to fix bugs in production, so you should seriously consider this kind of implementation. Of course you have to ask your player for a permission to send a bug report, because otherwise it may violate the agreement with Google Play or App Store and as a result your application may get banned.

I am personally using a script called SRDebugger from the Asset Store. It allows to display an overlay form that enables sending a bug report to my e-mail address.

Alternatives:

3. Try to recover

This is the third option and the only one that allows your game to work properly. I believe it should never be used, because if there’s a smoke then there’s a fire. Recovering is only hiding the smoke while you should start looking for the fire.

Assert GetComponent()

Remember that you should look for any issues as soon as possible. If your script is using a component sometime in the future, make sure to check at the beginning if this component is available.

Watch out for callbacks!

If your game includes callbacks that are called from external code and/or from another thread you may find yourself in a situation, when NullReferenceException is thrown out of nowhere. It can happen with Social API when callback may be invoked seconds after making a request. And at that time the object that made a request may… no longer exist.

OK, that’s not really true, but we can run into fake null issue here that we were talking about before. Let’s consider a scenario like this:

  1. Results scene is loaded.
  2. ResultsScreen script is requesting Social API for current player’s score.
  3. The player clicks on “main menu” button.
  4. Results scene is unloaded.
  5. Main menu scene is loaded.
  6. Social API callback is being invoked inside ResultsScreen script.

So if Results scene is unloaded, all of its objects should be destroyed at the time of executing sixth step. That’s not true, because the reference to ResultsScreen object is still valid and object exists, but it reports itself as null by faking its own null check as I explained in the previous article. It may look like this:

Can you guess where you will receive a NullReferenceException? On line 10 and it really doesn’t matter if ScoreLabel has been assigned or not. You won’t be able to access it at this point.

How to protect yourself from this kind of situations? The answer is strange but simple. You should do a null-check of this.

Yes, that’s right! Current object won’t be null because it simply cannot be, but since Unity is faking null checks, this is the best way to check if the current object can be still used!

Of course you can null-check all your objects that you’re about to use, but in more complicated scenarios this may be simply too much. Checking this for null should be good enough.

Keep calm and singletons

Singletons are often perceived as anti-pattern. Still singletons are widely used because of the simplicity and ease of implementation.

In the Unity most common type of singletons are:

  1. Singletons created on demand
  2. Singletons created by the engine (derived from MonoBehaviour)

Let’s look at the second type of singleton.

First, you should make sure that singleton Instance field is assigned as soon as possible, so I’m assigning it in Awake() method. But that’s not enough. There’s a serious risk that Awake() will not be called even once. This risk is caused by the assumption that Singleton object exists on the scene.

Knowing that, you have to create an assert in each class, where you intend to use this singleton:

Note that I’m assigning a singleton in Awake() function, but I’m testing it for null in Start() function instead of OnEnable() function.

That’s because Awake() and OnEnable() functions are called one after another for every enabled GameObject. It’s not explained too well in the official documentation, so I will try to clarify that.

There are scripts: ScriptA and ScriptB both with Awake(), OnEnable(), and Start() functions. The call order may look like this:

  1. ScriptA: Awake()
  2. ScriptA: OnEnable()
  3. ScriptB: Awake()
  4. ScriptB: OnEnable()
  5. ScriptA: Start()
  6. ScriptB: Start()

So as you can see, you cannot be sure that when you’re in OnEnable() that all singletons are assigned. The risk is even greater that sometimes singleton may be assigned, and sometimes not!

You can force your script to be initialized before anything else using Script Execution Order, but to be completely safe, don’t use singletons in Awake() and OnEnable().

Suggestions?

Do you have any other interesting suggestions on how to make your project robust by securing your code against NullReferenceExceptions? Please share your suggestions using the comment form below! We will appreciate it!

Mobile Optimization – Garbage Collector

What is the Garbage Collector? Let’s look at a definition on MSDN:

The .NET Framework’s garbage collector manages the allocation and release of memory for your application. Each time you create a new object, the common language runtime allocates memory for the object from the managed heap. As long as address space is available in the managed heap, the runtime continues to allocate space for new objects. However, memory is not infinite. Eventually the garbage collector must perform a collection in order to free some memory. […]

If C# or JavaScript is your first (and only) programming language then most probably you are not aware of how difficult is to manage application memory. In languages like C/C++ you have to decide when memory is allocated and when it is freed. Make one mistake, and you will either have a memory leak or your application will crash in an instant.

Of course if something is difficult to manage then it requires time to think about it. Now, we live in the world where we want to release our products to the market as soon as possible, so we’re trying to find a way to make everything as simple as possible. One of these things is allowing garbage collector to take care of freeing the memory.

Sounds great, doesn’t it? Yeah, garbage collection is a real life saver, but it has a downside too. Garbage collector runs from time to time and it requires your application to freeze for the time being (There’s a garbage collector mode that allows to run without freezing the app, but you’re not allowed to tune the Unity garbage collector settings.) and you have little control when the garbage collection should be launched. This is not an issue for a business application where the interface usually static, but may be an issue for a game where even a short pause can cause the player to loose the game. And what players hate the most is losing when it’s not their fault…

Garbage collector and games

Last time we talked a little about Unity profiler and garbage collection.  The rule is simple – we don’t want the garbage collector to start its job. To do so, we have to stop generating garbage. Of course it’s impossible not to generate garbage at all, but we can significantly reduce amount of generated garbage, so garbage collector will run once per ten minutes instead of once per ten seconds.

Using Pools

One of techniques to minimize the garbage is to reuse existing objects instead of creating new. This technique is called object pooling and we talked about it last time. In most cases you will benefit the most by using this technique, so this should be the first thing you should take care of.

There’s a great free library that you can use to build your own pools. It’s called Smooth.Foundations and it is available on the Asset Store. Unfortunately the website with its documentation is down, but the code is really simple to understand. Here’s an example pool that creates a pool of GameObjects with SpriteRenderer component.

From line 6 to 10 we create a delegate that defines how pool object should be created. From line 11 to 15 there’s code responsible for resetting the object to its original state (after releasing it).

Then the pool can be used this way:

Using Arrays

You may use arrays, but remember not to allocate these during the runtime. If any function needs to return an array of values, use an existing array and pass it as an argument.

Usual approach

GC-friendly approach

As you may have noticed, using gc-friendly code requires some more effort. First, you have to know the upper limit (in this case 32). You have to be sure that this limit is not exceeded, because your game will crash. Then if you want to iterate through these items, you have to use the size value instead of the size of an array.

Note that I used the ref keyword here. Ref means that this value should be passed by reference but since arrays are always passed by reference, it is not required in this case. The only reason it was used, was to increase the readability of GetNumbers() method call. If you see a ref then you know that something will get out that function using the passed parameter.

Using Lists

Using arrays directly may be not the best choice. Instead, you can use a List. The List in fact is an Array wrapped by a quite useful handling code, that guarantees you safety and you don’t need to worry about array sizes to much (and some other things too).

Yet you have to be careful. If you exceed the List array size, it will allocate a new bigger array. Since we want to minimize the number of allocations, always create lists using constructor that takes the capacity:

What about iterating through a list? You may know that or not, but Mono compiler that comes with Unity (Current Unity version at the time of writing this article is 5.2.3) has a bug that allocates memory when using foreach loop on collections. It’s not much because it is “only” 24 bytes, but executed many times will quickly exhaust your memory and trigger garbage collection. Instead, use for loop whenever possible.

Here’s an example code. Note that this time we don’t need a size variable.

Consolidating strings

There are some things that you simply cannot get around. One of those things is consolidating strings. When done, it will always allocate a new string. You can optimize this process a little by using StringBuilder instead of the add (+) operator.

The add (+) operator approach:

The StringBuilder approach:

Have you noticed that I used a using instruction to get a Disposable object from the pool? This is another method to use the pools. It’s much safer, because you won’t forget to take the borrowed object back.

Is that everything?

Of course it isn’t! One note though. Please, keep in mind that running your code in Unity editor will generate more garbage than running it on the target device. You may find yourself in a situation when you try to optimize the garbage when it is not generated at all on the target device. This is because the Unity does some nice optimizations when your game is build, and you always should run the profiler on already built game to know what should be optimized and what not.

Wrong Import Settings are Killing Your Unity Game [Part 2]

There are many things that may go wrong with your game development. Your models may have too many triangles for your target platform to handle, your algorithms may be too expensive for your CPU, and also you may be using too many materials so batching won’t work efficiently. These are difficult issues, and you as a game developer should always remember to keep good balance between visuals and performance. Yet, there are some things so simple that we often forget about their existence, but these can have a serious impact on your game performance.

Last time, in Part 1, we talked about how texture import settings can kill your game performance. This time we will talk about sound import settings and why it matters.

Audio Clip Import Settings

When working with Unity many things can keep their default settings set and everything will be working just fine. Of course, defaults are not optimal in most cases, but your game should be working OK. This rule unfortunately does not apply to Audio Clip Import Settings.

Audio Clip (sound files) importing is working very similar to texture importing. Unity supports many different audio formats, but in the end it converts them all to preferred (by the engine) format. Currently, in Unity 5.2.1 this can be PCM, ADPCM, Vorbis/MP3 and HEVAG. Note that not each platform can handle all of these compression formats, and some platforms have only one format available (e.g. WebGL can work only with AAC audio clips).

Memory matters

All Audio Clips are imported by default with “Decompress On Load” Load Type and “Vorbis” Compression Format.

These are default import settings.

These are default import settings.

You should be very careful with this setting, because using it on all your audio clips (Unity does it by default!) may consume large amount of your game’s memory! Do you see the info box on the screenshot? Original file size is computed to 35.9 MB and the imported size to 10.7 MB. This means that this Audio Clip will increase your game (archive) size by 10 megabytes, but playing it will require nearly 36 megabytes of RAM! This does not sound too scary if you’re building a game for PC where it is quite common to have 8 gigabytes of RAM, but mobile devices are still very limited on that manner.

When I should use specific Load Type?

Let’s get this straight. Each Load Type and Compression Format combination can be used and you’re the one who knows best which one should be chosen. There are three Load Types:

  • Compressed In Memory – Audio Clip will be stored in RAM and will be uncompressed when played. Does not require additional memory for playing.
  • Streaming – Audio Clip will be stored on a device persistent memory (hard drive, flash drive etc) and streamed when played. Does not require RAM for storing and playing (at least this value is not significant).
  • Decompress On Load – Audio Clip will be stored in RAM uncompressed. This option requires the most memory but playing it won’t require so much CPU power as the rest.

So, which one to use? It depends…

Music and/or Ambient Sounds

Music is stored in long Audio Clips so it can consume a lot of memory. For sure, we don’t want music to be decompressed into the memory then played. You have two options here:

  1. Use Load Type “Streaming” and Compression Format “Vorbis”. This combination will use the least amount of memory but will require some CPU power and disk I/O throughput.
  2. Use Load Type “Compressed In Memory” and Compression Format “Vorbis”. The only difference from the first solution is that it will exchange the disk I/O with some memory requirement. Note that you can adjust the Quality slider to decrease compressed clip size in exchange of sound quality. Usually 100 percent is a way too high. I would recommend something around 70 percent.

Note that if you have more than 2 music/ambient sounds clips playing like this, it can consume a serious amount of CPU power.

Sound Effects

Sounds effects are usually short or medium Audio Clips. Also these can be played frequently or rarely. Here are some rules:

  1. For frequently played and short Audio Clips use Decompress On Load and PCM or ADPCM Compression Format. When PCM is chosen, no decompression is needed and if audio clip is short it will load very quickly. You can also use ADPCM. It requires decompression, but it is much lighter to decompress than Vorbis.
  2. For frequently played but medium Audio Clips use Compressed In Memory and ADPCM Compression Format. ADPCM is around 3.5 times smaller than raw PCM and decompression algorithm will not consume as much CPU as Vorbis.
  3. For rarely played and short Audio Clips use Compressed In Memory and ADPCM. For the same reason as described in point 2.
  4. For rarely played and medium Audio Clips use Compressed In Memory  and Vorbis Compression Format. This SFX might be too long to be stored using ADPCM and played too rarely, therefore additional CPU power required to decompress wouldn’t be a such pain.

Summary

Always remember to check your Audio Clip Import Settings. These are silent performance killers of your game. Set these right, and you will get additional CPU power for things that matters.

Also please take a look at the manual for technical information about import settings.

Mobile Optimization with Unity Profiler

Mobile Optimization – Unity Profiler

In the previous Mobile Optimization series post we talked about how important the batching is. We talked about how to use Unity Profiler in order to inspect how many batches are actually made. Now we will talk a little more about the Profiler itself. If you already know about it you may learn something new!

The idea

The idea behind the Profiler is to provide as much timing, memory, and statistical information as possible. You can learn:

  • how long your game needs to compute and render a frame
  • What takes so long? (scripts, physics, graphics etc.)
  • the cause of spikes (short moments when your game fps is dropping)
  • what is generating garbage
  • how much memory the game allocates
  • and many more…

To access all this data you need to:

  1. Open the Profiler window from Windows -> Profiler main menu.
  2. Make sure that the Record button is enabled.
  3. Press the Play button and pause (or disable the Record button) when you want to analyze the collected data.

profiler record button

Note that it’s highly recommended to profile your game on target platform rather than in the Unity editor. You can do so by building a Development Build and by selecting Autoconnect Profiler in the build window. Although the second is not required, it will automatically start the profiling when the game is launched.

autoconnect profiler

Be aware that you’re required to own Android Pro or iOS Pro licenses to profile on Android or iOS platforms.

Deep look onto the Profiler Window

Let’s have a look at the Profiler window. You will learn everything that you need to know from the Unity manual, but we will now look at some part of it.

profiler window

  1. 1-3 are categories of profiling methods. There is more, but these three will be the most interesting. The first one is CPU Usage. Here you will learn the total time needed for your frame to compute and render. Times are categorized to Rendering, Scripts, Physics, etc.
  2.  Rendering category shows you information about Batches, SetPass Calls (formerly draw calls), Triangles and Vertices count.
  3. Memory category informs you about memory statistics. Be sure that your game is not consuming too much!
  4. This is CPU usage profiling section. Here you will find a lot more information about theUnity internals and your own scripts performance. This is information only about a single frame, so you have to click anywhere on the graph to select a frame. By default you’re able to expand some method calls only to level 1; enable Deep Profile (button at the bottom) to browse the script calls more deeply. Be careful with deep profiling. It requires a lot of memory and it makes your game run significantly slower.

The spikes

Let’s talk about spikes. This is usual term for situations when your game fps is significantly dropping for a split second. Why this is called a “spike”? That’s because in Profiler it looks just like a spike standing out the ground.

profiler spikes

Spikes are telling you that something caused, in this exact moment, that your frame is computed longer than usual. And you should inspect it.

 

I will list most known cause of spikes:

Garbage collector

If you know .NET platform well enough then most probably you’re aware of the garbage collector. If you don’t, imagine that all the memory that is allocated by your game at the runtime must be freed at some point, and this is also done at the runtime. This process is called garbage collection and it freezes your game until it is finished. Usually it can take only a fraction of a second, but this is more than enough to make your game feel laggy and unpleasant. The only way to target this issue is to prevent garbage collection from happening. We will look deeper into this matter in another blog post.

GameObject.Instantiate()

Instantiating objects during the game is one of the most expensive operations. When you’re instantiating an object, you are instantiating all its children including all the components. All script components requires to be properly initialized. This is easy way to generate quite a large spike.

To prevent this from happening, learn about object pooling. Simply talking you need to instantiate all possible needed objects at the beginning and hide them until needed. There are some pool scripts on the asset store that will help you handling that issue.

Scripts and expensive algorithms

Sometimes spikes will be generated by your own scripts. Maybe you’re doing too expensive operation that could be optimized or should be done in separate thread.

This kind of spikes are usually the easiest to fix, but most probably you will need to enable Deep Profile mode to make the Profiler to generate more information about your scripts performance. Many algorithms may be optimized. Those that cannot may be executed in coroutines or separate threads. Be aware that if you will decide to move your code to a separate thread, you shouldn’t call Unity API from within that thread. Instead you should use components like Dispatcher from UnityToolbag that will dispatch Unity API calls to the main thread.

Background processes and operating system itself

Sometimes you may experience spikes that are not your game’s fault. These spikes are displayed with a large amount of time assigned to Other category. This can be seen on operating systems that are allowing too many apps to run in the background (desktop operating systems or Android). This is not something that you can do about it, so kill as many background apps as possible, keep your Profiler open and observe if the spikes will go away. You can always try profiling it on a different device.

More tips

Mobile optimization is such a broad topic that it cannot be exhausted in a single blog post. Keep watching for new blog posts tagged with Mobile Optimization tag. There will be more! Next time we will talk about garbage collecting!

Wrong Import Settings are Killing Your Unity Game [Part 1]

There are many things that may go wrong with your game development. Your models may have too much triangles than your target platform can handle, your algorithms may be too expensive for your CPU, and also you may be using too many materials so batching won’t work efficiently. These are difficult issues, and you as a game developer should always remember to keep a good balance between visuals and performance. Yet, there are some things so simple that we often forget about their existence, but these can have a serious impact on your game performance.

Texture Import Settings

When you’re adding a texture into your project, the Unity works magic with it – the texture is converted to a suitable format based on current texture import settings. For most cases default settings will be good enough, but the Unity cannot tell if something looks good enough for the player so it cannot change it without your knowledge. It’s where you step in.

To access Texture Import Settings just select one or more textures that you want to change. Your inspector will look more or less like this:

texture import settings basicThere are 3 main things that you should keep an eye out.

Texture Type

texture type

Texture Type is a way to tell Unity what this texture will be used for. All this options besides Advanced will adjust your texture internal settings to be optimal as possible for the selected purpose. Note that texture of type Texture is a simple diffuse texture used in 3D space and for 3D game should be used the most. Types descriptions can be found in the official manual.

The risk: Setting the wrong texture type may be not noticeable at first and you will get a performance loss. Some types are required for shaders to work correctly (like Normal map type must be set for a texture that will be used for bump mapping).

Size

texture size and compression

This is where you can decide how big your texture should be and how it should be stored in the device memory. Noticed that there’s a Max Size instead of Size? This is simply because you can reduce all the textures resolution for your game in Quality Settings.

quality settings texture quality

Also setting the 2048 as Max Size won’t guarantee that this texture will be of that size even if Quality Settings are set to the highest. The texture resolution will be lower if your original texture file is not big enough. Knowing that, it is a good practice to prepare textures bigger than you need them to be, because you can always scale them down.

The Risk: Some models may be small on screen and those models’ textures can have large resolutions. You can identify these objects by setting your Scene shading to Mipmaps:

scene shading

Format

The texture Format is another thing that may be something confusing.

texture format

When your Texture Type is set to anything else than Advanced you will have 4 options.

  • Compressed – It trades a little of GPU power for a much lower texture size. Compressed option will use the most suitable compressing algorithm for your target platforms.
  • 16 bits – Saves the texture without a compression but it is using 16 bit color palette. Good for textures with small amount of colors.
  • Truecolor – Saves the texture using uncompressed 32 bit color palette. Looks great, but large 2048×2048 texture will require almost 17 megs of memory.
  • Crunched – Compressed using compression format suitable for the GPU and then compressed again using compression format that can be handled only by the CPU.  Good for downloadable asset bundles.

As you can see, you’re trading here texture size for texture quality. My advice is to always set the format as Compressed until you will see that something is not right with the textures in your game.

There’s one more Texture Type option that we haven’t described. If you set your Texture Type to advanced, you will gain access to many more texture formats including more compression methods. Be aware of that not all compression formats may be supported by your target platform (e.g. many Android devices have different texture compression formats support, but all should support ETC).

The Risk: Compressed textures may look ugly for some kind of textures, but textures set to 16 bits or Truecolor may take up too much space. You can find textures that are taking up to much space looking at editor.log after building your game.

You can learn more about texture compression formats here.

Verifying

texture import information

The last thing you want to do is to verify your texture import information. Here at the bottom of your texture preview you will learn about:

  • Used texture size
  • Used compression format
  • Result texture size

Keep in mind that sometimes you will need to build your game before you will see it’s target size.

Continued in Part 2 here

Side note: You may be wondering why textures sizes are power-of-two numbers. If you’re curious why, please read this discussion.