none
What List TrimExcess() does and when to use it RRS feed

  • Question

  • private void button2_Click(object sender, EventArgs e)
            {
                var before = System.Diagnostics.Process.GetCurrentProcess().VirtualMemorySize64;
    
                List<string> lst1 = new List<string>();
    
                for (int i = 0; i <= 1000000; i++)
                {
                    lst1.Add("Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test ");
                }
    
                var after = System.Diagnostics.Process.GetCurrentProcess().VirtualMemorySize64;
    
                lst1.Clear();
                lst1.TrimExcess();
    
                var current = System.Diagnostics.Process.GetCurrentProcess().VirtualMemorySize64;
            }

    i saw TrimExcess() clear memory for list instantly and it is bit better than list = null & GC.Collect....am i right?

    one request that please tell me what List TrimExcess() does and when to use it ? please come with a example which explain the objective of List TrimExcess() . i want to understand the actual usage of TrimExcess() function.

    thanks

    Thursday, April 11, 2019 7:37 PM

Answers

  • Remember, there are several different levels to consider here.  The List itself is an object.  It contains a set of object references.  Each of those references refers to an object.

    A List contains two important numbers: Size, and Capacity.  "Size" tells how many items are in the list right now.  "Capacity" is an internal thing that says how many references the List can currently hold.  The capacity is not reduced when you remove an item as an optimization, since you're likely to add more items later.  If you add 8 items to a list and then remove 3 of them, Size will be 5, and Capacity will still be 8.  Of those 8 list entries, 5 of them point to real objects, and 3 of them are null.

    All that TrimExcess does is to set Capacity = Size, which shortens its list from 8 references to 5 references. Those 3 null references don't take up very much space, so it's not really very important unless the list has many, many entries and you know you won't need that many any more.  There is no advantage at all in the scenario you have above.

    Remember, the list itself is just a set of references.  The string objects themselves are all deleted when you call lst1.Clear().  What you're left with is 1,000,000 references to null.  lst1.TrimExcess() reduces that to 0 references.  You will STILL have a List object.  Setting lst1 = null; will free up the list object as well, so if you're through with the list, it is better.  In this particular case, none of that is necessary, because the list will be deleted when it goes out of scope anyway.

    As the documentation says, TrimExcess can be used if your list was very large, but is now small, and will not get large again.  If you are emptying a list, it's probably better to assign null to it.


    Tim Roberts | Driver MVP Emeritus | Providenza &amp; Boekelheide, Inc.

    • Marked as answer by Sudip_inn Sunday, April 14, 2019 10:19 AM
    Thursday, April 11, 2019 10:31 PM
  • Hi Sudip_inn,

    Thank you for posting here.


    The first thing you need to understand is the capacity of List < T > .

    If you don't specify the container size of list,the default is 0. As long as there are elements added, it will automatically expand to 4. If the fifth element is added,  become 8. If the ninth element is added, it will be 16.As you can see, it always doubles growth. When expanding, it is necessary to reclaim memory, it will cause memory wastes and affect efficiency .At this point, you can call the TrimExcess method to release excess memory.

    Sample Code:
    List<int> value = new List<int>(4);
    // Count:0 Capacity: 4
                
    for (int i = 1; i <= 5; i++)
    {
        value.Add(i);
    }
    // Count:5 Capacity: 8            
    
    value.TrimExcess();
    // Count:5 Capacity: 5
                
    
    //remove an item
    value.RemoveAt(4);
    // Count:4 Capacity: 5
    value.TrimExcess();
    // Count:4 Capacity: 5
    
    //remove another item
    value.RemoveAt(1);
    // Count:3 Capacity: 5
    value.TrimExcess();
    // Count:3 Capacity: 3
    
    value.Clear();
    // Count:0 Capacity: 3
    value.TrimExcess();
    // Count:0 Capacity: 0
    
    Hope it  helps you.
    Best regards,
    Jack



    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    • Marked as answer by Sudip_inn Sunday, April 14, 2019 11:07 AM
    Friday, April 12, 2019 3:26 AM
    Moderator

All replies

  • There is documentation and code samples here

    https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.trimexcess?view=netframework-4.7.2


    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    Thursday, April 11, 2019 7:47 PM
    Moderator
  • Remember, there are several different levels to consider here.  The List itself is an object.  It contains a set of object references.  Each of those references refers to an object.

    A List contains two important numbers: Size, and Capacity.  "Size" tells how many items are in the list right now.  "Capacity" is an internal thing that says how many references the List can currently hold.  The capacity is not reduced when you remove an item as an optimization, since you're likely to add more items later.  If you add 8 items to a list and then remove 3 of them, Size will be 5, and Capacity will still be 8.  Of those 8 list entries, 5 of them point to real objects, and 3 of them are null.

    All that TrimExcess does is to set Capacity = Size, which shortens its list from 8 references to 5 references. Those 3 null references don't take up very much space, so it's not really very important unless the list has many, many entries and you know you won't need that many any more.  There is no advantage at all in the scenario you have above.

    Remember, the list itself is just a set of references.  The string objects themselves are all deleted when you call lst1.Clear().  What you're left with is 1,000,000 references to null.  lst1.TrimExcess() reduces that to 0 references.  You will STILL have a List object.  Setting lst1 = null; will free up the list object as well, so if you're through with the list, it is better.  In this particular case, none of that is necessary, because the list will be deleted when it goes out of scope anyway.

    As the documentation says, TrimExcess can be used if your list was very large, but is now small, and will not get large again.  If you are emptying a list, it's probably better to assign null to it.


    Tim Roberts | Driver MVP Emeritus | Providenza &amp; Boekelheide, Inc.

    • Marked as answer by Sudip_inn Sunday, April 14, 2019 10:19 AM
    Thursday, April 11, 2019 10:31 PM
  • Hi Sudip_inn,

    Thank you for posting here.


    The first thing you need to understand is the capacity of List < T > .

    If you don't specify the container size of list,the default is 0. As long as there are elements added, it will automatically expand to 4. If the fifth element is added,  become 8. If the ninth element is added, it will be 16.As you can see, it always doubles growth. When expanding, it is necessary to reclaim memory, it will cause memory wastes and affect efficiency .At this point, you can call the TrimExcess method to release excess memory.

    Sample Code:
    List<int> value = new List<int>(4);
    // Count:0 Capacity: 4
                
    for (int i = 1; i <= 5; i++)
    {
        value.Add(i);
    }
    // Count:5 Capacity: 8            
    
    value.TrimExcess();
    // Count:5 Capacity: 5
                
    
    //remove an item
    value.RemoveAt(4);
    // Count:4 Capacity: 5
    value.TrimExcess();
    // Count:4 Capacity: 5
    
    //remove another item
    value.RemoveAt(1);
    // Count:3 Capacity: 5
    value.TrimExcess();
    // Count:3 Capacity: 3
    
    value.Clear();
    // Count:0 Capacity: 3
    value.TrimExcess();
    // Count:0 Capacity: 0
    
    Hope it  helps you.
    Best regards,
    Jack



    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    • Marked as answer by Sudip_inn Sunday, April 14, 2019 11:07 AM
    Friday, April 12, 2019 3:26 AM
    Moderator
  • i have populate so many list one after one with huge data. i was clearing memory like this way

    List1=null ;
    
    GC.Collect();
    
    List2=null ;
    
    GC.Collect();
    
    List3=null ;
    
    GC.Collect();

    is t good approach ? because here i call GC.Collect() many times.....does it degrade my code performance ?

    second question

    later i use List1.Clear() & List1.TrimExcess() instead of list1=null & GC.Collect()

    tell me which approach is good.


    Sunday, April 14, 2019 11:05 AM
  • i have populate so many list one after one with huge data. i was clearing memory like this way

    List1=null ;
    
    GC.Collect();
    
    List2=null ;
    
    GC.Collect();
    
    List3=null ;
    
    GC.Collect();

    is t good approach ? because here i call GC.Collect() many times.....does it degrade my code performance ?

    second question

    later i use List1.Clear() & List1.TrimExcess() instead of list1=null & GC.Collect()

    tell me which approach is good.

    Sunday, April 14, 2019 11:07 AM
  • Hi Studip_inn,

    Recommend the following combinations:

    List1.Clear() & List1.TrimExcess()

    Frequent invocation GC.Collect() to clean up resources at a point in the program where it usually wouldn't ,will weaken the optimization of GC. For more information, please refer to the following articles:


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Monday, April 15, 2019 7:54 AM
    Moderator
  • Yes, GC.Collect() costs in performance.  Why are you worried about this?  The runtime will do garbage collection on its own when it has the time to do so.  You don't have to force it.  GC.Collect is designed for unusual circumstances where the runtime might not notice the need.

    Mostly, you are prematurely optimizing here, nitpicking over unimportant details.  If you will use the list again, then

        list1.Clear();  list1.TrimExcess();

    leaves the list object intact so you can start filling it again, whereas

        list1 = null;

    also frees up the list object itself.  That's only a few bytes of memory.

    FIRST, make your code work.  THEN, figure out where it is slow and fix that.  If it's not slow, don't worry about microoptimization.


    Tim Roberts | Driver MVP Emeritus | Providenza &amp; Boekelheide, Inc.

    Monday, April 15, 2019 10:03 PM