Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 768409
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 14, 20262026-05-14T18:10:35+00:00 2026-05-14T18:10:35+00:00

When I perform a AppDomain.Unload(myDomain) I expect it to also do a full garbage

  • 0

When I perform a AppDomain.Unload(myDomain) I expect it to also do a full garbage collection.

According to Jeffrey Richter in “CLR via C#” he says that during an AppDomain.Unload:

The CLR forces a garbage collection to occur, reclaiming the memory used by any objects
that were created by the now unloaded AppDomain. The Finalize methods for
these objects are called, giving the objects a chance to clean themselves up properly.

According to “Steven Pratschner” in “Customizing .NET Framework Common Language Runtime”:

After all finalizers have run and no more threads are executing in the domain, the CLR is ready to unload all the in-memory data structures used in the internal implementation. Before this happens, however, the objects that resided in the domain must be collected. After the next garbage collection occurs, the application domain data structures are unloaded from the process address space and the domain is considered unloaded.

Am I misinterpreting their words?
I did the following solution to reproduce the unexpected behavior (in .net 2.0 sp2):

An class library project called “Interfaces” containing this interface:

   public interface IXmlClass
    {
        void AllocateMemory(int size);

        void Collect();
    }

A class library project called “ClassLibrary1” which references “Interfaces” and contains this class:

public class XmlClass : MarshalByRefObject, IXmlClass
{

    private byte[] b;

    public void AllocateMemory(int size)
    {
        this.b = new byte[size];
    }

    public void Collect()
    {
        Console.WriteLine("Call explicit GC.Collect() in " + AppDomain.CurrentDomain.FriendlyName + " Collect() method");
        GC.Collect();
        Console.WriteLine("Number of collections: Gen0:{0} Gen1:{1} Gen2:{2}", GC.CollectionCount(0), GC.CollectionCount(1), GC.CollectionCount(2));
    }

    ~XmlClass()
    {
        Console.WriteLine("Finalizing in AppDomain {0}", AppDomain.CurrentDomain.FriendlyName);
    }
}

A console application project which references “Interfaces” project and does the following logic:

static void Main(string[] args)
{
    AssemblyName an = AssemblyName.GetAssemblyName("ClassLibrary1.dll");
    AppDomain appDomain2 = AppDomain.CreateDomain("MyDomain", null, AppDomain.CurrentDomain.SetupInformation);
    IXmlClass c1 = (IXmlClass)appDomain2.CreateInstanceAndUnwrap(an.FullName, "ClassLibrary1.XmlClass");
    Console.WriteLine("Loaded Domain {0}", appDomain2.FriendlyName);
    int tenmb = 1024 * 10000;
    c1.AllocateMemory(tenmb);
    Console.WriteLine("Number of collections: Gen0:{0} Gen1:{1} Gen2:{2}", GC.CollectionCount(0), GC.CollectionCount(1), GC.CollectionCount(2));
    c1.Collect();
    Console.WriteLine("Unloaded Domain{0}", appDomain2.FriendlyName);
    AppDomain.Unload(appDomain2);
    Console.WriteLine("Number of collections after unloading appdomain:  Gen0:{0} Gen1:{1} Gen2:{2}", GC.CollectionCount(0), GC.CollectionCount(1), GC.CollectionCount(2));
    Console.WriteLine("Perform explicit GC.Collect() in Default Domain");
    GC.Collect();
    Console.WriteLine("Number of collections: Gen0:{0} Gen1:{1} Gen2:{2}", GC.CollectionCount(0), GC.CollectionCount(1), GC.CollectionCount(2));
    Console.ReadKey();
}

The output when running the console application is:

Loaded Domain MyDomain
Number of collections: Gen0:0 Gen1:0 Gen2:0
Call explicit GC.Collect() in MyDomain Collect() method
Number of collections: Gen0:1 Gen1:1 Gen2:1
Unloaded Domain MyDomain
Finalizing in AppDomain MyDomain
Number of collections after unloading appdomain:  Gen0:1 Gen1:1 Gen2:1
Perform explicit GC.Collect() in Default Domain
Number of collections: Gen0:2 Gen1:2 Gen2:2

Things to notice:

  1. Garbage collection is done per process (just a refresher)

  2. Objects in the appdomain that gets unloaded have the finalizer called but garbage collection is not done. The 10 megabyte object created by AllocateMemory() will only be collected after performing an explicit GC.Collect() in the above example (or if the garbage collector will at some time later.

Other notes: it doesn’t really matter if XmlClass is finalizable or not. The same behavior occurs in the above example.

Questions:

  1. Why does calling AppDomain.Unload doesn’t result in a garbage collection? Is there any way to make that call result in a garbage collection?

  2. Inside AllocateMemory() I plan to load short lived large xml documents (less or equal to 16 mb) that will get on LargeObject heap and will be generation 2 objects. Is there any way to have the memory collected without resorting to explicit GC.Collect() or other kind of explicit programmatic control of garbage collector?

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-14T18:10:36+00:00Added an answer on May 14, 2026 at 6:10 pm

    Additional Notes:

    After some mail exchange with Jeffrey Richter who was kind enough to have a look at the question:

    OK, I read your post.
    First, the array will not be GC’d until the XMLClass object is GC’d and it takes TWO GCs to collect this object because it contains a Finalize method.
    Second, unloading an appdomain at least performs the marking phase of the GC since this is the only way to determine which objects are unreachable so that their Finalize methods can be called.
    However, the compact part of the GC might or might not be done when unloading a GC.
    Calling GC.CollectionCount obvious does not tell the whole story. It is not showing that the GC marking phase did occur.
    And, it’s possible that AppDomain.Unload starts a GC via some internal code which does not cause the collection count variables to be incremented. We already know for a fact that the marking phase is being performed and that collection count is not reflecting this.

    A better test would be to look at some object addresses in the debugger and see if compaction actually occurs. If it does (and I suspect it does), then the collection count is just not being updated correctly.

    If you want to post this to the web site as my response, you can.

    After taking his advice and looking into SOS (also removed the finalizer) it revealed this:

    Before AppDomain.Unload:

    !EEHeap -gc
    Number of GC Heaps: 1
    generation 0 starts at 0x0180b1f0
    generation 1 starts at 0x017d100c
    generation 2 starts at 0x017d1000
    ephemeral segment allocation context: none
     segment    begin allocated     size
    017d0000 017d1000  01811ff4 0x00040ff4(266228)
    Large object heap starts at 0x027d1000
     segment    begin allocated     size
    027d0000 027d1000  02f75470 0x007a4470(8012912)
    Total Size  0x7e5464(8279140)
    ------------------------------
    GC Heap Size  0x7e5464(8279140)
    

    After AppDomain.Unload (same addresses, no heap compaction was done)

    !EEHeap -gc
    Number of GC Heaps: 1
    generation 0 starts at 0x0180b1f0
    generation 1 starts at 0x017d100c
    generation 2 starts at 0x017d1000
    ephemeral segment allocation context: none
     segment    begin allocated     size
    017d0000 017d1000  01811ff4 0x00040ff4(266228)
    Large object heap starts at 0x027d1000
     segment    begin allocated     size
    027d0000 027d1000  02f75470 0x007a4470(8012912)
    Total Size  0x7e5464(8279140)
    ------------------------------
    GC Heap Size  0x7e5464(8279140)
    

    After GC.Collect(), addresses differ indicating heap compaction was done.

    !EEHeap -gc
    Number of GC Heaps: 1
    generation 0 starts at 0x01811234
    generation 1 starts at 0x0180b1f0
    generation 2 starts at 0x017d1000
    ephemeral segment allocation context: none
     segment    begin allocated     size
    017d0000 017d1000  01811ff4 0x00040ff4(266228)
    Large object heap starts at 0x027d1000
     segment    begin allocated     size
    027d0000 027d1000  027d3240 0x00002240(8768)
    Total Size   0x43234(274996)
    ------------------------------
    GC Heap Size   0x43234(274996)
    

    After more sos the conclusion I’ve reached is that it is surely by design, and that heap compaction is not necessarily done. The only thing you can really be sure during an AppDomain unload is that objects will get to be marked as unreachable and will be collected during the next garbage collection (which like I said, it’s not done exactly when you unload your application domain, unless there’s a coincidence).

    EDIT: I’ve also asked Maoni Stephens, who works directly in the GC team. You can read her response somewhere in the comments here. She confirms that it is by design.
    Case closed 🙂

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

We perform updates of large text files by writing new records to a temp
I'm trying to perform a LINQ query on a DataTable object and bizarrely I
How do I perform an IF...THEN in an SQL SELECT statement? For example: SELECT
I'm trying to perform a SQL query through a linked SSAS server. The initial
How do I perform a reverse DNS lookup, that is how do I resolve
How do you perform the equivalent of Oracle's DESCRIBE TABLE in PostgreSQL with psql
In order to perform a case-sensitive search/replace on a table in a SQL Server
I want to perform cascade delete for some tables in my database, but I'm
How do I perform a network login, to access a shared driver for instance,
I'm trying to perform a bitwise NOT in SQL Server. I'd like to do

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.