Navigation |
>> Home |
The ReDim Preserve Performance Trap
Written by: Christoph Wille Whoever works with arrays in VB will be familiar with the ReDim statement for resizing arrays. Today, I will explain in detail why you better shouldn't use this statement in the future, or at least very, very carefully consider its use. The possible uses of ReDimBefore attacking the ReDim statement and disheveling it, I want to show its most common uses by means of a code sample (redimsamples.aspx). It will show a simple ReDim, as well as a ReDim Preserve: <% @Page Language="VB" %> <% Dim arrStrings(1) as String Response.Write(UBound(arrStrings) & "<br>") ReDim arrStrings(20) Response.Write(UBound(arrStrings) & "<br>") ReDim Preserve arrStrings(25) Response.Write(UBound(arrStrings) & "<br>") %> ReDim allows increasing as well as decreasing an array's size. For this, a new array is created in each instance. The reason for this is that the VB.NET array is a descendant of the System.Array of the .NET Runtime which by definition has a fixed size on creation. In C# this is obvious, as is demonstrated by the following code emulating ReDim: string[] arrTest = new string[1]; // and now we want to change the size: ReDim arrTest(20) arrTest = new string[20]; In itself, this is no problem, the trouble starts with Preserve (today's topic). When using Redim with the Preserve keyword, the old elements are preserved - as copies in the new array. ReDim Preserve as a Performance KillerIn principle, we already spoiled the whole story - the ReDim Preserve statement creates a new array - and the elements of the old array get copied into the new one. As this happens under VB.NET (as it does under the "old" VB) implicitly, it won't be noticed except for performance loss. To give a somewhat drastic impression of that I set up a loop which redims an array five thousand times (redimloop.aspx). <% @Page Language="VB" Trace="True" %> <% Dim arrStrings() as String Dim i as Integer Trace.Write("Redim","Start") For i = 1 To 5000 ReDim Preserve arrStrings(i) arrStrings(i-1) = i Next Trace.Write("Redim","End") %> As I switched on tracing, it is easy to obtain performance data: Of course, this will differ with each call (and with the machine), but at least you get some indication of relative performance. But what happens in the background when calling ReDim Preserve? To illustrate that, I emulated the ReDim statement in C#, as everything done by ReDim in VB.NET automagically in the background, has to be done explicitly there (redimloopexplicit.aspx). <% @Page Language="C#" Trace="True" %> <% string[] arrStrings = new string[1]; int i; Trace.Write("Redim","Start"); for (i=1;i<=5000;i++) { string[] arrHelper = new string[i]; arrStrings.CopyTo(arrHelper, 0); arrHelper[i-1] = i.ToString(); arrStrings = arrHelper; } Trace.Write("Redim","End"); %> Here we can clearly see how bad performance must be - firstly, an array of the new size is created and then the contents of the old array are copied to the new one. The iteration variable is assigned with me performing the cast to String in C# myself. And for finishers, I swap the array variables. Whoever thinks that VB.NET does something differently is wrong - performance is exactly the same as for ReDim Preserve (my code perhaps is a little better as it doesn't take decreasing the array's size into account). How bad performance actually is can only be realized by comparing it to a superior technology - the ArrayList class. The Best Solution - ArrayListsThe best solution for a dynamic array is the ArrayList class in the System.Collections namespace. An ArrayList can dynamically grow or shrink, and is very easy to use (arraylistloop.aspx): <% @Page Language="VB" Trace="True" %> <% @Import Namespace="System.Collections" %> <% Dim arrList as New ArrayList(100) Dim i as Long Trace.Write("ArrayList","Start") For i = 1 To 50000 arrList.Add(i) Next Trace.Write("ArrayList","End") %> Those who took a closer look will have noticed that the loop isn't running to five thousand, but to fifty thousand. The reason for that is: with five thousand, performance couldn't be measured. But with fifty thousand, it still is quite impressive: Execution time is 0.01 to 0.45 - and that with an order of magnitude more loop iterations! I intended to let ReDim Preserve run with this number of iterations as well, but I just reset the server some time during that run... ConclusionThe lesson to be taken from this article is that under VB.NET ReDim Preserve is something to be positively avoided. When dynamic arrays are needed, it is advisable to use an ArrayList as that basically behaves like a normal array. Downloading the CodeClick here, to start the download.
©2000-2004 AspHeute.com |