33

I have a list called Population, is a great list of very many positions and at some point I stop using it. How I can free the resources? Then this is part of the code:

 private List <BasePopulation> Population=new List <BasePopulation>();
 Population.SomeMethod();
 Population.Clear();

I used the Clear method, but not works. Any idea?

Brian Gideon
  • 47,849
  • 13
  • 107
  • 150
Esneyder
  • 471
  • 1
  • 5
  • 19
  • 12
    Let the [Garbage Collector](http://msdn.microsoft.com/en-us/library/ms228629%28v=vs.90%29.aspx) do its job. – Pierre-Luc Pineault Jul 30 '13 at 19:08
  • How do you know it doesn't work? If you are looking at the Working Set bytes, that might not be an accurate way to measure it: http://stackoverflow.com/questions/1984186/what-is-private-bytes-virtual-bytes-working-set – Greg Jul 30 '13 at 20:16
  • 1
    @Pierre-LucPineault: It may not be that obvious. See my answer. – Brian Gideon Jul 30 '13 at 20:18

5 Answers5

40

The problem may be that Clear is not doing what you think it is. Clear simply marks the List as being empty without resizing the internal array that it uses behind the scenes. It will, however, remove all references to the individual BasePopulation instances. So if no other data structure has a reference to them they will be eligible for garbage collection. But, it will not reduce the size of the List directly. I just verified this using ILSpy.

You have two options.

  1. Set Population = null. This will unroot the entire object instance making it eligible for garbage collection.

  2. Call TrimExcess on this List. This will resize the internal array.

Brian Gideon
  • 47,849
  • 13
  • 107
  • 150
  • 1
    Isn't setting the list to null redundant? If I recall correctly, the object is eligible for GC as soon as the Jitter detects it won't be ever read again, not when the reference goes null. – Pierre-Luc Pineault Jul 30 '13 at 20:32
  • 3
    @Pierre-LucPineault: You are correct. Well, except that is for **local** references. For **class member** references like the one in the question the garbage collector cannot perform the same optimization since it would be difficult (or possible) to predict whether or not it would be read in the future. – Brian Gideon Jul 30 '13 at 20:45
  • @BrianGideon: I also have similar issue. I have list in C# which contains many items. I want to free the memory this list occupies. So that I can add new items to the list. What is the best way to free this memory? – Giorgi Moniava Mar 30 '15 at 15:55
  • @Giorgi: Is there any reason #1 or #2 in my answer would not work for you? – Brian Gideon Mar 31 '15 at 01:52
  • @BrianGideon: I'll use #1. Set list reference to NULL. I need to add items to list. But I can NULL list every time I add say some fixed number of items to it, e.g., after I added 100 000 items, I will NULL it so that I can add another 100 000 etc. (because I don't need old ones anymore). is it ok? – Giorgi Moniava Mar 31 '15 at 07:48
  • @Giorgi: You wouldn't technically need to `null` it out in that case. Just doing a `mylist = new List()` will have the same effect. – Brian Gideon Mar 31 '15 at 15:45
  • @Brian Gideon: thanks-i was thinking garbage collection might not occur immediately-read somewhere in c# it don't happen this way. – Giorgi Moniava Mar 31 '15 at 18:27
  • @Giorgi: You're right. GC won't happen immediately. You could use `GC.Collect` to make that happen, but it's generally frowned upon. – Brian Gideon Mar 31 '15 at 19:01
  • @BrianGideon Option 2 works because TrimExcess will do `this.Capacity = 0` (if the list was cleared before). You could just "cut out the middle man" and call `list.Capacity = 0` yourself. – Tim Dec 01 '15 at 17:09
12

Well, since the garbage collector (GC) is taking care of the memory management for you, the first thing you can do is getting rid of all references to the list (and the contained elements) so that the GC is able to remove it on the next occasion. You can do this, for example, by explicitly setting

Population = null;

If this isn't enough for you, for example because you're really eager to get rid of the objects now and you can accept non-optimal run-time behaviour, you can tell the GC to start collecting objects now via

GC.Collect();

More information about this method can be found here.

As indicated above, this practice can induce a performance penalty since it forces the GC to clean up resources at a point in the program where it usually wouldn't. Directly calling the method is thus often discouraged, but it might serve your needs if this is really a special point in your application. As a practical example, I've successfully improved peak memory usage in a program that requires a lot of objects during an initialization that can be discarded once the actual program execution has started. Here, the small performance penalty for calling GC.Collect() after the initialization was justifiable.

Bobby Tait
  • 99
  • 1
  • 8
bigge
  • 1,488
  • 15
  • 27
  • However there's no guarantee that `GC.Collect()` will collect this precise Population object. It will reclaim stuff, but not necessarily everything. – Pierre-Luc Pineault Jul 30 '13 at 19:45
  • Yep, exactly true. But at least it's worth a try if the circumstances fit (see my update) – bigge Jul 30 '13 at 19:46
  • 2
    I've read that `Population = null;` can make things worse. It constitutes a reference to `Population`, so delays GC until after that reference. You'd be better to do nothing at all. – John Saunders Jul 30 '13 at 19:47
  • But if you don't get rid of the references to the objects, there's no way that the GC will be able to collect the objects (except if the object containing `Population` itself is beeing collected) – bigge Jul 30 '13 at 19:49
  • Setting a reference to `null` is a valid way of unrooting the object it was pointing to. In fact it might be the only way. Think of a singleton class that holds a large `byte[]` (class member). How else are you going to unroot it when it's not needed anymore? I really don't see anything wrong with this answer. Am I missing something? – Brian Gideon Jul 30 '13 at 19:57
3

The best possible thing you could do is nothing. Garbage Collector GC does this job automatically for you. Since List is not IDisposable you cannot dispose it.

Clear would simply remove elements from the List but wouldn't dispose it.

Venkata Krishna
  • 14,926
  • 5
  • 42
  • 56
3

You must clear the list, and after that invoke the GC to remove it from memory. As follows with extensive method:

public static void ClearMemory<T>(this List<T> lista)
{
    int identificador = GC.GetGeneration(lista);
    lista.Clear();
    GC.Collect(identificador, GCCollectionMode.Forced);
}
-3

Edit, rewording my answer about Disposing. Ok, I must have been imagining things when I typed Clean. I'm assuming that if clearing all of the items from your list is not free resources, then the resources you are trying to free up are unmanaged. Based upon that assumption you'll need BasePopulation to implement IDisposable so when that object gets picked up by the garbage collector, those resources can then be released.

http://msdn.microsoft.com/en-us/library/system.idisposable.aspx

Glenn Cuevas
  • 166
  • 5