Tasharen Entertainment Forum

Support => NGUI 3 Support => Topic started by: Disastercake on August 05, 2012, 04:50:23 PM

Title: What is BetterList?
Post by: Disastercake on August 05, 2012, 04:50:23 PM
I saw in the recent update:

Quote
- FIX: Replaced most usages of List with BetterList instead in order to significantly reduce memory allocation.

What exactly is BetterList?  A google search does not seem to find any relevant information for me.
Title: Re: What is BetterList?
Post by: ArenMook on August 05, 2012, 06:35:53 PM
It's a class I wrote in NGUI. Every time you add an item to a regular List, it re-allocates a new array. This is terrible for performance and garbage collection. Same thing happens when you remove items. BetterList doesn't do this, and behaves more like std::vector, if you're familiar with C++ -- it grows its size only when necessary, and does so in chunks, rather than 1 by 1.
Title: Re: What is BetterList?
Post by: maul on February 15, 2014, 06:25:55 AM
Hi! Is this still the case? I don't know a lot about .NET and mono internals, but it would seem ridiculous for List to allocate memory item-by-item and to throw away the internal array on Clear().
Title: Re: What is BetterList?
Post by: ArenMook on February 16, 2014, 02:05:20 AM
Unity hasn't updated their version of mono in many years, so yes, it's still true.
Title: Re: What is BetterList?
Post by: junkier on March 28, 2014, 06:24:40 AM
Every time you add an item to a regular List, it re-allocates a new array. This is terrible for performance and garbage collection. Same thing happens when you remove items.
Unity hasn't updated their version of mono in many years, so yes, it's still true.

Hi there!
I was very surprised when I have seen BetterList class. And I was wondering, why System.Collections.Generic.List is so bad, and came there to find answer.
I've performed simple test in Unity Editor (Unity 4.3.4, Unity 3.5 .net full Base Class Libraries), that has shown, as I expected, that System.Collections.Generic.List works well, as expected, with memory.
Please see my example code below:

using System.Collections.Generic;

var list = new List<int>();
Debug.Log("Initial capacity: " + list.Capacity);
for (int i = 0; i < 10; ++i)
{
  list.Add(i);
  Debug.Log(string.Format("Added element '{0}'. Current capacity = {1}", i, list.Capacity));
}

list.Clear();
Debug.Log("List capacity after clear: " + list.Capacity);

// Filling list for second time
for (int i = 0; i < 10; ++i)
{
  list.Add(i);
  Debug.Log(string.Format("Added element '{0}'. Current capacity = {1}", i, list.Capacity));
}

list.Clear();
Debug.Log("List capacity after clear: " + list.Capacity);

And the result:

Quote
Initial capacity: 0
Added element '0'. Current capacity = 4
Added element '1'. Current capacity = 4
Added element '2'. Current capacity = 4
Added element '3'. Current capacity = 4
Added element '4'. Current capacity = 8
Added element '5'. Current capacity = 8
Added element '6'. Current capacity = 8
Added element '7'. Current capacity = 8
Added element '8'. Current capacity = 16
Added element '9'. Current capacity = 16
List capacity after clear: 16
Added element '0'. Current capacity = 16
Added element '1'. Current capacity = 16
Added element '2'. Current capacity = 16
Added element '3'. Current capacity = 16
Added element '4'. Current capacity = 16
Added element '5'. Current capacity = 16
Added element '6'. Current capacity = 16
Added element '7'. Current capacity = 16
Added element '8'. Current capacity = 16
Added element '9'. Current capacity = 16
List capacity after clear: 16

So, as we can see, new array allocated only when we trying to add more elements than capacity allows. If you know beforehand how much elements you are going to have in a list, you can pass this number to List's constructor, and it will allocate in memory array with corresponsind size.
All what I'm trying to say, that now System.Collections.Generic.List is working in Unity just like MSDN says (http://msdn.microsoft.com/en-us/library/6sh2ey19(v=vs.80).aspx) (at least for .NET 3.5).

Title: Re: What is BetterList?
Post by: ArenMook on March 28, 2014, 08:45:46 AM
In my test I had 2 lists -- one list always pre-allocated with 1 million integers, and a second list which iterated through the first and added the integers to the 2nd list one at a time. At the end of the for loop it would Clear() the second list, so the next frame the process would repeat again.

I monitored performance via a stopwatch as well as GC collection / spikes in the profiler window. FWIW my test was done back in Unity 3.4 days.