Category Archives: Unity3d

Unity3d – Profiling calls to Destroy

Destroy All … Things

I’ve recently been investigating some performance problems in our Unity3d app.  In one specific instance (running full screen on a rubbish laptop), there were numerous large performance spikes caused by the nebulous-sounding “Destroy”.  After prodding a little bit, Destroy is related to calling GameObject.Destroy().

Unfortunately, Unity3d’s profiler won’t give you any information related to what types of objects are being destroyed, and wrapping your GameObject.Destroy calls in profiler sections doesn’t help, as Unity3d defers the work for later in the frame (so the methods return nigh-on immediately).  As such, you get told “Destroy is taking x ms this frame”, and that’s about it.

Finding the culprits with the profiler

I managed to work around this limitation by (temporarily) changing all GameObject.Destroy() method calls to GameObject.DestroyImmediate() then wrapping the calls in Profiler.BeginSample() / Profiler.EndSample() pairs.

Note: If you access your unity instances in the same frame after calling destroy, this probably won’t work for you.

It was then possible to see which resources were doing the damage on the laptop.  All of our resource cleanup code was in one place, so it was trivial to do.

The temporarily instrumented code ended up looking something like this, and immediately let us know the culprits.  Note this code is just a simplified mockup, but it should give you the gist of the idea:

// centralised resource cleanup makes profiling simple
private void CleanupResources<TResource>()
{
    Profiler.BeginSample("Destroy: " + typeof(TResource).Name);
    IEnumerable<TResource> resources = FindResourceOfType(typeof(TResource));
    foreach(var resource in resources)
    {
        resource.Dispose();
    }
    Profiler.EndSample();   
}

//… and each Resource type inherits from a common base class, implementing IDisposable.
public abstract class Resource : IDisposable
{
    protected abstract void CleanupUnityResources();
   
    public void Dispose()
    {
        CleanupUnityResources();
    }
}

public class SomeResource : Resource
{
    private Mesh m_unityMesh; // gets set when resource is locked in
   
    protected override void CleanupUnityResources()
    {
        // GameObject.Destroy(m_unityMesh);
        GameObject.DestroyImmediately(m_unityMesh);
    }
}

Unity3d–Threadpool Exceptions

A quickie, but something to be very wary of.  I’ve been using Unity3d of late (I recommend it – it’s a very opinionated and sometimes quirky bit of software, but it generally works well) and I was recently tasked to parallelise some CPU intensive work. 

I decided, quite reasonably, to use the built-in ThreadPool rather than doing my own explicit management of threads, mainly because the work we’re parallelising is sporadic in nature, and it’s easier to use the ThreadPool as a quick first implementation.  So far, so good.  Everything was going swimmingly, and it appeared to work as advertised.  In fact, the main implementation took less than a day.

Most .NET developers who are familiar with doing threading with the ThreadPool will know that, post .NET 1.1, if an unhandled exception occurs on a ThreadPool thread, the default behaviour of the CLR runtime is to kill the application.  This makes total sense, as you can no longer guarantee a program’s consistency once an unhandled exception occurs. 

To cut a long story short, I spent about three days debugging a very subtle bug with a 1 in 20 reproduction rate (oh threading, how I love thee).  Some methods were running and never returning a result, yet no exceptions were reported. 

Eventually I reached a point where I’d covered nearly everything in my code and was staring at a Select Is Broken situation (in that Unity3d had to be doing something weird).

Unity3d silently eats ThreadPool exceptions!  I proved this by immediately throwing an exception in my worker method and looking at the Unity3d editor for any warnings of exceptions – none was reported (at the very least, they should be sending these exceptions to the editor). 

I then wrapped my worker code in a try catch and, when I finally got the 1 in 20 case to occur, sure enough, there was an exception that was killing my application’s consistency.  So yes, I did have a threading bug in my application code, but Unity3d’s cheerful gobbling of exceptions meant the issue was hidden from me.

I’ve bugged the issue, so hopefully it’ll get fixed in future.

Note: To the people who say “you should be handling those exceptions in the first place”, I would say, “not during development”. When developing, I generally want my programs to die horribly when something goes wrong, and that is the expected behaviour for the .NET ThreadPool.  Unhandled exceptions make it clear that there’s a problem and it means the problem must be fixed.