Sponsored By Aspose - File Format APIs for .NET

Aspose are the market leader of .NET APIs for file business formats – natively work with DOCX, XLSX, PPT, PDF, MSG, MPP, images formats and many more!

An Application Domain Example – Level 000

The other day, I talked about What is an application domain – an explanation for .Net beginners. Now that we know what an application domain is, lets explore one of the ways we can use it.

One common use for application domains is to use them to execute
code that is memory intensive.  You can load up another assembly,
in this case an executable, and run it in a seperate application
domain.  Once the execution has completed, you get rid of the
application domain and the system gets that memory back.  Because
you have executed the code in a seperate application domain from the
default domain, the garbage collector isn’t going to run on your heap
in your default domain.  Pretty nifty eh?  So lets look at
the absolute simplest example I could come up with.  We are going
to create to exe files.  One is going to use up a bunch of memory
and occasionally output its state to the console.  The other is
going to be our main exe that loads up an application domain and
executes our memory intestive operations, and then tosses the
application domain away.  I create a directory c:\AppDomainExample
for both of these files.

BuildStrings.cs

using System;

 

public class BuildStrings

{

               public static void Main()

               {

                             
// This is meant to be a bad example.  This example will create a new string 10001 times, because String.Concat creates a new string

                             
// each time you add another string
to it, so its going to suck up a bunch of memory.  You can also
make the number of concats larger
                             
// up to a million or so and that
will cause 300+ gen0 GC’s to occur, which is something else we’d rather
have happen to somebody
                             
// else’s heap instead of the heap
for our default application domain.  But, because the default
application will be waiting on the
                             
// code below to execute,
performance is still an issue because it will still impact the
appearance of theoveral time required for
                             
//
the main application domain to execute its own code.

                             
Console.WriteLine(“I am running from application domain: ” + System.Threading.Thread.GetDomain().FriendlyName);

                             
string text1 = “A”;

                             
int num1 = 0;

                             
int num2 = 0;

                             
do

                             
{

                                            
text1 = text1 + “A”;

                                            
num1++;

                                            
num2++;

                                            
if (num2 == 1000)

                                            
{

                                                           
Console.WriteLine(“{0} concats.”,num1);

                                                           
num2 = 0;

                                            
}

                                                           

                             
}

                             
while (num1 <= 10000);

                             
Console.WriteLine(“Done!”);

               }

}

Now compile that with csc BuildStrings.cs

AppDomainExample.cs

using System;

 

public class AppDomainExample

{

static void Main()

                             
{

                                            
// The following code creates an application domain with a default security policy and  with the setup info we use to specify where the application is located

                                            
AppDomainSetup setupInfo = new AppDomainSetup();

                                            
setupInfo.ApplicationBase = @”C:\AppDomainExample”;

                                            
AppDomain appDomain = AppDomain.CreateDomain(“BuildStringsDomain”, null, setupInfo);

 

                                            
// The next line of code execute the assembly

                                            
appDomain.ExecuteAssembly(“BuildStrings.exe”);

 

                                            
// Now get rid of the appDomain.  You cannot unload individual assemblies from an application domain.  You can only unload the entire domain object.

                                            
AppDomain.Unload(appDomain);

                             
}

}

Now compile that with csc AppDomainExample.cs

When you go to the command line and execue AppDomainExample.exe, you get the following output:

So there you have it! We have created some assemblies, created an
application domain, executed the code inside of it and then unloaded
the application domain.  Next time we’ll look at it more in depth
and explore some of the overloaded methods for creating an application
domain and executing an assembly, including invoking methods and
passing parameters.  I’ll also provide some CLRProfiler graphs so
you can see what the CLR is really doing behind the scenes.

This entry was posted in .Net Development. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

9 Responses to An Application Domain Example – Level 000

  1. R.K.T. Ashoka says:

    Hi thanks for your example..

    I tried creating the above sample as windows application, that is I created a memory intensive windows forms application and created another Windows forms application which will load the memory intensive application.. But I got the following error:
    An unhandled exception of type ‘System.IO.FileNotFoundException’ occurred in mscorlib.dll

    Additional information: File or assembly name WinBuildStrings.exe, or one of its dependencies, was not found.

    where WinBuildStrings.exe is the memory intesive windows forms application..

    I am new to AppDomains so sorry if my question was silly…

  2. Sam says:

    Great post! Just thought I’d add my two cents: Other places you might find a new AppDomain useful are: What if your process just locks up? You don’t really see this much in .NET land, but one way to do it right quick is a sloppy RegularExpression. How can you keep the regex from killing your app? Execute it in a new AppDomain, then if your process times out you have the chance to recover gracefully by killing the spawned AppDomain.

    Another usage would be in a case where you want to unload Type information. You can only do this with an AppDomain (as far as I’ve read).

    Yet another case: Automatic/easy updates. You want your app to check for updates, if they’re available, you want it to download, install, and load the new version all automatically (or after the user accepting the update, whatever the case may be). How do you do it? You have a lock on the resources you’re executing from after all. Well, you could use a “boot-strap” that the user executes. To them it looks like the application, but really it’s just a splash screen that handles updates, and if current, loads your assemblies. Since you’re only locking the boot-strap application you’re free to update the rest of your assemblies to your heart’s content and only load them when you want to. Now automated remote updates are a piece of cake!

  3. Ari says:

    Thanks again! I am looking forward to your future blogs :)

  4. Ari says:

    Thanks Raymond for the detailed response!
    Have I understood correctly that the advantage of running BuildStrings.Main() in its own AppDomain as opposed to running it within the AppDomainExample AppDomain is twofold:
    – eliminiates the risk that BuildString.Main() could cause AppDomainExample.Main() to crash?
    – does not fragment AppDomainExample heap?

    It seems to me that the number of times the GC runs should be the same for both approaches, is that incorrect?

  5. rlewallen says:

    Ari,

    “The GC should not collect any objects that are referred to (except for objects referred to from unmanaged code), so why is this an issue?” What you have to understand about this specific example is how the CLR handles it all. String.Concat will create a new string each time you add an “A” to it. By the time you have added “A” 1000 times, you have 1001 instances of a string. You’ll have “A”, “AA”, “AAA”, “AAAA”, “AAAAA” and so one. Once you get to “AAAAA”, the “A” and “AA” and “AAA” and “AAAA” are no longer needed or referenced. When memory consuption reaches a certain level, the GC will clean those up. So in the particular example that I have shown, that is where the issue lies. In a more complex scenario involving some sort of memory intesive operation, it becomes a bigger issue when the GC starts running every 60ms because of the extraordinary amount of objects that are being created and then being de-referenced shortly thereafter.

    “you do not wish the GC to run where it is not needed?” – Never. Every time the GC runs that is a very expensive operation. GC running a lot of times on a app that is creating and destroying objects like crazy also causes fragmentation on the heap. We want to keep those adverse effects away from our default application domain where AppDomainExample resides, and put all that work in a seperate “Process” (application domain) so that it is isolated from everything else. If something were to fail or throw an excpetion with BuildStrings, it only fails in our BuildStringsDomain and will not crash our default domain. We isolate the intestive and hard-working but quick process away into its own domain so that it will have less of an impact on our primary, default application domain that is hosting our main executable.

    I hope that helps, and thanks for reading!

  6. Ari says:

    Hi Raymond and thanks for your good blog.

    You say “[b]ecause you have executed the code in a seperate application domain from the default domain, the garbage collector isn’t going to run on your heap in your default domain.” I wondering what would be the benefit of that? The GC should not collect any objects that are referred to (except for objects referred to from unmanaged code), so why is this an issue? Is this perhaps a performance issue? I.e., you do not wish the GC to run where it is not needed? Or is it a memory issue? I.e., do you wish to free up the memory immediately? If so, could you then not just call GC.collect() after BuildStrings.Main() has run?

    I am a relative newcomer to C# and have been wondering about the usefulness of application domains, so I hope you bear with me if my question is stupid :)

  7. Mark says:

    Nice. A simple, yet very useful example.

    –Mark

  8. johnpapa says:

    Pretty cool.

Leave a Reply