2

I'm looking for a List<T> type class in .NET which behaves similar to List<T> but doesn't de-allocate its memory when Clear() is called - only resets the Size property.

My aim is to use this class in a memory pool, so I want the memory to be maintained, but have the caller use the class as though it were a standard list, but to avoid lots of memory re-allocations.

If this already exists please let me know as it will save time optimizing, testing and debugging this code.

Here is a mockup of what I'm hoping to find in the .NET library:

public class ReusableList<T>
{
    #region Static Properties

    private static long InitialCapacity = 1000000;
    private static int CapacityIncreaseRate = 10000;

    #endregion

    #region Properties

    public long Size
    {
        get
        {
            return this._size;
        }
        private set
        {
            this._size = 0;
        }
    }
    private long _size = 0;

    private long RealSize
    {
        get
        {
            return this._realSize;
        }
        set
        {
            this._realSize = value;
        }
    }
    private long _realSize = 0;

    private T[] Data
    {
        set
        {
            this._data = value;
        }
        get
        {
            return this._data;
        }
    }
    private T[] _data = null;

    #endregion

    #region Operators

    public T this[long index]
    {
        get
        {
            return this.Data[index];
        }
        set
        {
            this.Data[index] = value;
        }
    }

    #endregion

    #region Public Methods

    public ReusableList()
    {
        this.Rebuild();
    }

    public void Add(T item)
    {
        this.Data[this.Size] = item;

        this._size++;

        if (this.Size >= this.RealSize)
        {
            this.IncreaseSizeOfList();
        }
    }

    public void Clear()
    {
        this.Size = 0;
    }

    #endregion

    #region Private Methods

    private void Rebuild()
    {
        this.Data = null;

        this.Data = new T[ReusableList<T>.InitialCapacity];

        this.Size = 0;

        this.RealSize = ReusableList<T>.InitialCapacity;
    }

    private void IncreaseSizeOfList()
    {
        if (this.Size < this.RealSize)
            return;

        var newData = new T[this.RealSize + ReusableList<T>.CapacityIncreaseRate];

        Array.Copy(this.Data, newData, this.RealSize);

        this.Data = newData;

        this.RealSize += ReusableList<T>.CapacityIncreaseRate;
    }

    #endregion
}
rhughes
  • 9,257
  • 11
  • 59
  • 87
  • Did you think of inheriting a LinkedList? – jdweng Apr 23 '16 at 11:43
  • @jdweng What did you have in mind? – rhughes Apr 23 '16 at 11:49
  • Why not just implement `IList` with the semantics that you want? Your concrete class can have the methods you need for specific memory management. – casperOne Apr 23 '16 at 11:49
  • 2
    @casperOne I'm happy to do this, but want to first see if there is a similar class already in the framework as this may save a lot of time. – rhughes Apr 23 '16 at 11:52
  • Instead of deleting item move deleted item to garbage pile. When adding insert from garbage pile. If garbage pile is empty add new item. – jdweng Apr 23 '16 at 13:23
  • 1
    If the goal is to implement an object pool, maybe [this answer](http://stackoverflow.com/a/30664859/3159635) could be of help as DotNetCore is right around the corner? – AGB May 11 '16 at 02:08

2 Answers2

1

As far as I understand, this is default behavior of List<T>.

When you add items to list, it allocates new memory, if needed. When you remove items (or even clear list at all), it neither "frees" memory nor decreases size of internal array.

The only way to decrease internal array is to decrease Capacity. You can look into source code yourself. E.g., here's Clear method:

public void Clear() 
{
    if (_size > 0)
    {
        Array.Clear(_items, 0, _size);
        _size = 0;
    }
    _version++;
}

As you can see, here's only setting array items to defaults and setting size to 0.

AGB
  • 2,230
  • 1
  • 14
  • 21
Dennis
  • 37,026
  • 10
  • 82
  • 150
  • 1
    The comment for `Array.Clear` states: `Sets length elements in array to 0 (or null for Object arrays)`. Would calling `Array.Clear` free that memory if the GC was invoked? – rhughes Apr 23 '16 at 14:16
  • There are several implementations of [`IList.Clear`](https://msdn.microsoft.com/en-us/library/system.collections.ilist.clear(v=vs.110).aspx) in the BCL, and many (including `List`) include the following: [`Array.Clear(_array, 0, _size); // Don't need to doc this but we clear the elements so that the gc can reclaim the references.`](http://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,303). `Array.Clear` allows the GC to reclaim references previously in use. – AGB May 11 '16 at 02:01
0

You can store a backup of internal list.

public class ReusableList<T> : List<T>
{
    private List<T> backup;

    public void Clear(bool purge)
    {
        if (purge)
            backup?.Clear();
        else
            backup = this.ToList();

        base.Clear();
    }

    public new void Clear()
    {
        this.Clear(false);
    }
}
Hamid Pourjam
  • 20,441
  • 9
  • 58
  • 74