Infosys Microsoft Alliance and Solutions blog

« Impersonation and Delegation - There is too much confusion! | Main | Business capabilities met on the cloud »

Multiple AppDomains and Loader Optimizations

In my earlier blog Working with Application Domains in WPF, I had touched upon the usage of LoaderOptimization attribute. In recent days I have been playing around with WinDBG and hence thought to see how this attribute really affected to loading of assemblies and memory consumption of the application.

I used the the same application as mentioned in my earlier blog and handled 3 cases

1. No loader optimization
2. LoaderOptimization.MultiDomainHost
3. LoaderOptimization.MultiDomain

In all 3 cases, I ran the application and took the memory dump after launching the other appdomain. The physical size of memory dump file for option 2 was smaller than that for option 1, which is expected since we expect the assemblies to not be loaded multiple times.

Following is what I observed from WinDBG. Note that the output shown below is truncated in many places so that I can highlight the relevant pieces only.

Doing a !dumpdomain for the first case (without loader optimizations) showed the results as

0:000> !dumpdomain
--------------------------------------
System Domain: 6841d058
LowFrequencyHeap: 6841d07c
HighFrequencyHeap: 6841d0c8
StubHeap: 6841d114
Stage: OPEN
Name: None
--------------------------------------
Shared Domain: 6841c9a8
LowFrequencyHeap: 6841c9cc
HighFrequencyHeap: 6841ca18
StubHeap: 6841ca64
Stage: OPEN
Name: None
Assembly: 0025a1f8
--------------------------------------
Domain 1: 00262f58
LowFrequencyHeap: 00262f7c
HighFrequencyHeap: 00262fc8
StubHeap: 00263014
Stage: OPEN
SecurityDescriptor: 002688f8
Name: WPFAppDominTest.exe
Assembly: 0025a1f8 [C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll]
ClassLoader: 0025a268
SecurityDescriptor: 002790b0
  Module Name
63d41000 C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll
00232354 C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\sortkey.nlp
00232010 C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\sorttbls.nlp
00232698 C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\xjis.nlp

Assembly: 0025a3b8 [D:\Work\Code\VS2008\WPF\WPFAppDominTest\WPFAppDominTest\bin\Debug\WPFAppDominTest.exe]
........................................
........................................
........................................
--------------------------------------
Domain 2: 076d1838
LowFrequencyHeap: 076d185c
HighFrequencyHeap: 076d18a8
StubHeap: 076d18f4
Stage: OPEN
SecurityDescriptor: 0027ea60
Name: test
Assembly: 0025a1f8 [C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll]
ClassLoader: 0025a268
SecurityDescriptor: 0030e648
  Module Name
63d41000 C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll
00232354 C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\sortkey.nlp
00232010 C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\sorttbls.nlp
00232698 C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\xjis.nlp

Assembly: 003228b8 [D:\Work\Code\VS2008\WPF\WPFAppDominTest\DummyApp\bin\Debug\DummyApp.exe]
........................................
........................................
........................................ 

The key things to note in the above output are
1.  There are 4 domains created for the process. The first two are standard (System and Shared) and the third is hosting the application that I was running - WPFAppDominTest. The forth is the test domain that I created in code and used to launch DummyApp.

2. The Shared domain hosts only mscorlib at the address 0025a1f8. This same assembly is shared with Domain 1 and Domain 2 as can be seen by the address for this assembly in these domains in the output above.

3. I can additionally verify by doing a !dumpassembly and confirming that the Parent Domain matches with the address of Shared Domain.

0:000> !dumpassembly 0025a1f8
Parent Domain: 6841c9a8
Name: C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll
ClassLoader: 0025a268
SecurityDescriptor: 000ccc88
  Module Name
63d41000 C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll
00232354 C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\sortkey.nlp
00232010 C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\sorttbls.nlp
00232698 C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\xjis.nlp

4. There are other assemblies also loaded in Domain 1 and 2 which are common, but since no optimization is done, they are loaded twice. For example, let's check on WindowsBase.dll

Domain 1: Assembly: 0025a7a8 [C:\Windows\assembly\GAC_MSIL\WindowsBase\3.0.0.0__31bf3856ad364e35\WindowsBase.dll]

Domain 2: Assembly: 00322b58 [C:\Windows\assembly\GAC_MSIL\WindowsBase\3.0.0.0__31bf3856ad364e35\WindowsBase.dll]

You can see that the addresses are different. It is this aspect that we address when we use loader optimization. Let's now look at option 2 where we used LoaderOptimization.MultiDomainHost attribute. The significant change is seen in the Shared domain in this case, as seen below

--------------------------------------
Shared Domain: 6841c9a8
LowFrequencyHeap: 6841c9cc
HighFrequencyHeap: 6841ca18
StubHeap: 6841ca64
Stage: OPEN
Name: None
Assembly: 0025a7a8
Assembly: 0025a968
Assembly: 0025a888
Assembly: 002c0090
Assembly: 0025a1f8
Assembly: 0025a6c8

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

You will notice that unlike the single mscorlib earlier, we now have a total of 6 assemblies loaded in Shared domain. The dump for Domain 1 and 2 in this case will confirm that some assemblies loaded in there are at these addresses and essentially are the same assemblies. Thus we get the benefit of loading these additional 5 assemblies only once and this helps reduce the memory foot print and also the load time, since these 5 assemblies need not be loaded again. So which are these additional 5 assemblies. In my case, these are

WindowsBase.dll
PresentationCore.dll
PresentationFramework.dll
PresentationFramework.Aero.dll
System.dll

These can be confirmed by doing a !dumpassembly on all the assembly addresses shown in Shared domain. Eventually I tested for option 3 as well where I used the LoaderOptimization.MultiDomain attribute. The difference between this and LoaderOptimization.MultiDomainHost attribute as per the documentation is that in the former maximum possible resources will be loaded in shared mode and in the later only assemblies from GAC should be loaded in shared domain. This means that if I use LoaderOptimization.MultiDomain attribute I should possibly see more assemblies loaded in Shared domain and this is confirmed by taking a dump and analyzing in WinDBG.

--------------------------------------
Shared Domain: 6841c9a8
LowFrequencyHeap: 6841c9cc
HighFrequencyHeap: 6841ca18
StubHeap: 6841ca64
Stage: OPEN
Name: None
Assembly: 004998a8
Assembly: 003ba818
Assembly: 003ba9d8
Assembly: 003ba428
Assembly: 00499a68
Assembly: 003ba8f8
Assembly: 0041ca50
Assembly: 003ba1f8
Assembly: 003ba738
Assembly: 00499bb8
Assembly: 00499c98
--------------------------------------

Notice that in case the shared domain has total of 10 assemblies loaded (excluding mscorlib). Running !dumpassembly on above addresses I realized the following additional assemblies were loaded in shared domain

WPFAppDomainTest
DummyApp
WpfControlLibrary2
System.Xml
System.Configuration

In this case, the WPFAppDomainTest was really used only in Domain 1 and DummyApp and WpfControlLibrary2 only in Domain 2, so loading these in shared domain doesn't really gives any specific advantage and hence we should only use LoaderOptimization.MultiDomainHost attribute. However in your case, based on your assembly usage pattern, you can decide which attribute works better for you.

The one aspect that I didnot understand was the loading of System.Xml and System.Configuration assemblies. These are assemblies that reside in GAC and hence as per definition should have been loaded in shared domain even when I had used the LoaderOptimization.MultiDomainHost attribute. I haven't been able to figure this out as yet. If you have an idea on this, do share. And In case you want to understand more about assembly loading and domain neutral assemblies (those loaded in shared domain) you can check this MSDN entry.

Post a comment

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)

Please key in the two words you see in the box to validate your identity as an authentic user and reduce spam.

Subscribe to this blog's feed

Follow us on

Blogger Profiles

Infosys on Twitter