Nico Vuyge's blog

Taking the blue AND the red pill

When is an assembly loaded?

Nico Vuyge

What triggers the loading of an assembly?

A client recently asked me to take a look at the startup speed of his application. The application is a WinForms application that will be deployed via http deployment. One particular problem with this application was that it loaded a lot of unneeded assemblies before the first screen was shown. This severely impacted the startup speed when using http deployment, because all the referenced assemblies need to be downloaded first. Using google, I couldn't find much information on what triggers the loading of an assembly. Then I remembered I heard something on this topic in a session on WinForms performance optimisation at the 2003 PDC (this is one of the reasons of going to the PDC). So I dug up my conference DVD and listened to this session (CLI211, "Windows Forms Tips and Tricks", by Shawn Burke) again. Shawn mentions the following reasons why .NET needs to load an assembly:

  1. When the CLR loads a type, it also loads the types of any member variables the type has.
  2. When a method is JITted, all types referenced in that method are loaded. In order to speed up the loading of the application, we want to defer the loading of the referenced assemblies as much as possible. Shawn gives some advice on how to delay the loading of assemblies: Situation 1 can be prevented by changing the type of the member variable to Object, and access the member variable via a property that does a cast:
public LibraryA.ClassA memberDependency;

becomes

object objProperty;
public LibraryA.ClassA PropertyDependency
{
    get
    {
        return objProperty as LibraryA.ClassA;
    }
    set
    {
        objProperty = value;
    }
}
    

LibraryA will now only be loaded when the get accessor is JITted, rather than when the type containing this property is loaded. Situation 2 can be prevented by moving parts of the code to a separate method:

void foo()
{
    if (condition)
    {
        //main path
    }
    else
    {
        LibraryA.ClassA A;
        //do something with A 
    }            
}
    

becomes

void callA()
{
    LibraryA.ClassA A;
    //do something with A 
}
void foo()
{
    if (condition)
    {
        //main path
    }
    else
    {
        callA();
    }            
}
        

foo doesn't reference ClassA anymore, so the assembly LibraryA won't be loaded anymore when the method foo is JITTed.

Much too my surprise, after I had modified the application to delay the loading of all those assemblies, the assemblies still loaded too early. So I decide to do some experiments to find out if there are any other reasons that trigger the loading of an assembly.

Next: Experimenting with assembly load time.