OutOfMemory & CompiledAssembly

Problems seem to occur in batches. Last week the hot topic was OutOfMemory exceptions.

I got a memory dump that a customer took around the time they were getting OutOfMemory exceptions. I asked them to collect some performance counters so that we could figure out what this leak was all about.

The performance counters we got were

.NET CLR Loading\Current Assemblies

Process\Private Bytes

Process\Virtual Bytes

.NET CLR Memory\# Bytes in all heaps

.NET CLR Memory\# Total committed bytes

.NET CLR Memory\# Total reserved bytes

The picture below shows the output.

Perfmon

The line that keeps increasing matches “Current Assemblies”. Now this is strange since usually after a while this should stop increasing. So it appears we are having assembly leaking.

Let’s try to find what these assemblies are.

0:000> !DumpDynamicAssemblies

Domain: xxxxxxx

-------------------

Assembly: 0x15ba5ab0 [-fxq0b2q] Dynamic Module: 0x15bbc7c0 loaded at: 0x170a1000 Size: 0xf000((null))

Assembly: 0x15bb52f0 [m_o9jngq] Dynamic Module: 0x224830 loaded at: 0x17421000 Size: 0x26000((null))

Assembly: 0x15bb5868 [dgttiya4] Dynamic Module: 0x224ed0 loaded at: 0x17451000 Size: 0x1200((null))

Assembly: 0x1748ee30 [tfgs3roi] Dynamic Module: 0x1748b7a0 loaded at: 0x17e11000 Size: 0x1b000((null))

Assembly: 0x15bc54f0 [xw0tr4my] Dynamic Module: 0x15bc5928 loaded at: 0x1e7b1000 Size: 0x1fd000((null))

At the time this memory dump was taken we had almost 2000 dynamic assemblies in memory. Digging into some of these assemblies ...

0:000> !savemodule 0x1748b7a0 c:\leak.dll

Successfully saved file: c:\leak.dll

And opening them with Lutz Reflector we find a pattern

public class _DinAssembly

{

    public bool _method1()

    {

        return true;

    }

}

After talking with dev teams and doing some search in source code we found that this assembly is being generated in source code.

(…)

results.CompiledAssembly.CreateInstance

(…)

If you look at

http://msdn.microsoft.com/en-us/library/system.codedom.compiler.compilerresults.compiledassembly.aspx

you can see

Note:

(…) After calling the get accessor, the compiled assembly cannot be deleted until the current AppDomain is unloaded.

So some possible solutions are:

· Try some caching mechanism (if it´s possible)

· Load this assemblies into a separated domain so that you could unload it

· Do you really need to generate this assembly?

Bruno