C# List Memory not collected

2019-09-21 11:15发布

问题:

This code allocates memory, but never frees the memory. How do I force collection of the memory, GC.Collect() does not seem to work either.

I have reviewed many posts that ask this question but everyone answers that the garbage collector will take care of the memory, but it never does.

    var list = new List<string>();

    for (var i = 0; i < 10000000; i++)
    {
      list.Add("really long string..................................................................................................");
    }

    for (var i = 0; i < 10000000; i++)
    {
      list[i] = null;
    }

    list.Clear();

回答1:

Here's the code of List<T>.Clear:

// Clears the contents of List.
public void Clear() {
    if (_size > 0)
    {
        Array.Clear(_items, 0, _size); // Don't need to doc this but we clear the elements so that the gc can reclaim the references.
        _size = 0;
    }
    _version++;
}

As you can see, the array is kept allocated as-is. This is done for efficiency reasons. The array is already allocated, there's no need let the GC collect it as it will probably be needed again.

You can set the Capacity property to force it to reallocate a new array. This will actually add memory pressure (unless you set it to 0) until the previous array gets collected. Here's the code for reference:

// Gets and sets the capacity of this list.  The capacity is the size of
// the internal array used to hold items.  When set, the internal 
// array of the list is reallocated to the given capacity.
// 
public int Capacity {
    get {
        Contract.Ensures(Contract.Result<int>() >= 0);
        return _items.Length;
    }
    set {
        if (value < _size) {
            ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value, ExceptionResource.ArgumentOutOfRange_SmallCapacity);
        }
        Contract.EndContractBlock();

        if (value != _items.Length) {
            if (value > 0) {
                T[] newItems = new T[value];
                if (_size > 0) {
                    Array.Copy(_items, 0, newItems, 0, _size);
                }
                _items = newItems;
            }
            else {
                _items = _emptyArray;
            }
        }
    }
}

As for your really long string, it's just a reference to an interned string... The list will store 8 bytes per item anyway (assuming a 64-bit system).



回答2:

If you explicitly call GC.Collect() it doesn't mean that it's going to be collected immediately. GC will decide when to collect...