Advantages of Cecil over DefaultAssemblyReflector?

Dec 14, 2010 at 7:26 AM

Looking at the code if I choose not to distribute Mono.Addins.CecilReflector.dll then DefaultAssemblyReflector will be created as the IAssemblyReflector. What are the advantages of using Mono.Addins.CecilReflector? For us, its a trade off between shipping the Cecil library of 355KB and the advantages/disadvantages.

Great framework by the way!

Coordinator
Jan 12, 2011 at 12:27 PM

Short answer: DefaultAssemblyReflector is a bit faster and makes the app smaller. CecilReflector is more robust, but a bit slower.

Now the long answer: Mono.Addins has an add-in scanner which is in charge of scanning all assemblies of an application and extract the add-in information it later needs to load and resolve extensions. This scanner is currently being run in a separate app domain of the application. To do its job, it has to load every single assembly it finds in the project directory (and all other included add-in directories) in memory, and DefaultAssemblyReflector uses System.Reflection to do it. For medium and small applications this should not be a problem. Assemblies are loaded, scanned, and when the domain unloads, the assemblies will be unloaded (if .NET/Mono does its job right). Also notice that assemblies are only scanned the first time the app is started, and when they change.

However, for big applications, there may be scalability issues. If the application is composed my many assemblies, the memory taken by the scanner may grow too much. Assemblies loaded with reflection won't be unloaded until the app domain is unloaded. Also, there may be runtime conflicts issues. For example, let's say the main exe of your application is compiled using .NET 3.5, but in the same directory you have another exe compiled with .NET 4.0. When you run the main exe, it will try to scan the 4.0 assembly and it will fail. And finally there can also be conflicts between the loaded assemblies (e.g. loading the same assembly from different locations and things like that). The Mono.Cecil based reflector doesn't have all this problems, because doesn't use System.Reflection, but its own object model for loading assemblies. Assemblies can be GCed as soon as they are scanned, and there is no possibility of conflicts, since Mono.Cecil can load assemblies from any runtime version, doesn't matter what's the executing runtime.

In summary: if you have tested your application with DefaultAssemblyReflector and works fine, then you don't need CecilReflector. If your application is big and complex (maybe composed by several exes) and you want to be on the safe side, CecilReflector is maybe a better option.

Jan 12, 2011 at 12:50 PM
Edited Jan 12, 2011 at 1:00 PM

Thanks for the reply. I'm using CecilReflector at the moment with no noticeable speed issues. I'm more concerned with memory requirements. When starting the application after an application update (dll changed) the private bytes of the process is double what it usually is. Stopping the application and starting it again fixes memory to the lower number again. I know this is because of the scanning that's taking place on start up. Do both DefaultAssemblyReflector and CecilReflector make use of a separate app domain? I would think the memory would drop down soon after the scan completes but persists while the application stays running.

 

Edit: Just ran some more tests and I don't have this memory problem when I use DefaultAssemblyReflector (no CecilReflector). The memory stays nice and low even after a scan. Looks like DefaultAssemblyReflector may be the way to go for me.

Coordinator
Jan 12, 2011 at 2:28 PM

This is weird. There should be no memory issues with CecilReflector. Are you using Mono or .NET? Are you using Mono.Addins 0.5?

Jan 12, 2011 at 2:47 PM

Mono.Addins 0.5 on .NET

Jan 12, 2011 at 3:06 PM

Did a bit of profiling with CLR Profiler. A scan with CecilReflector causes the managed heap to grow significantly. Lots of System.String and System.Byte are allocated. This does not happen with DefaultAssemblyReflector. Note: The memory allocated with CecilReflector does get GC'd so its not a leak or anything. I just prefer DefaultAssemblyReflector as depending on the .NET memory manager the managed heap can stay at a larger size even if its mostly empty.