Improving .NET Application Performance Part 13: Arrays

Improving .NET Application Performance Part 13: ArraysIn our previous article in the .NET series we discussed the how to optimize String operations in .NET. In this article we’ll focus on optimizing arrays.

Arrays provide basic functionality for grouping types. Every language implements array syntax in its own way, although the following considerations apply regardless of language:

  • Arrays have a static size. The size of the array remains fixed after initial allocation. If you need to extend the size of the array, you must create a new array of the required size and then copy the elements from the old array.
  • Arrays support indexed access. To access an item in an array, you can use its index.
  • Arrays support enumerator access. You can access items in the array by enumerating through the contents using the foreach construct (C#) or For Each (Visual Basic .NET).
  • Memory is contiguous. The CLR arranges arrays in contiguous memory space, which provides fast item access.

This section summarizes performance guidelines to consider when using arrays:

  • Prefer arrays to collections unless you need functionality.
  • Use strongly typed arrays.
  • Use jagged arrays instead of multidimensional arrays.

Prefer Arrays to Collections Unless You Need Functionality

Arrays are the fastest of all collections, so unless you need special functionality, such as dynamic extension of the collection, you should consider using arrays rather than collections. Arrays also avoid the boxing and unboxing overhead.

Use Strongly Typed Arrays

Use strongly typed arrays where possible, rather than using object arrays to store types. This avoids type conversion or boxing depending upon the type stored in the array. If you declare an array of objects and then proceed to add a value type such as an integer or float to the array, it involves the boxing overhead as shown in the following code sample.

Object[] array = new Object[10]

arr[0] = 2+3; //boxing occurs here


To avoid the boxing overhead declare a strongly typed int array, as follows:

int [] arrIn = new int [10];

arrIn[0] = 2+3;

Storing reference types, such as string or custom classes in the array of objects, involves the typecasting overhead. Therefore, use strongly typed arrays to store your reference types to, as shown in the following code sample.

string[10]  arrStr = new string[10];

arrStr[0] =  new string(“abc”);

Use Jagged Arrays Instead of Multidimensional Arrays

A jagged array is a single dimensional array of arrays. The elements of a jagged array can be of different dimensions and sizes. Use jagged arrays instead of multidimensional arrays to benefit from MSIL performance optimizations.

MSIL has specific instructions that target single dimensional zero-based arrays (SZArrays) and access to this type of array is optimized. In contrast, multidimensional arrays are accessed using the same generic code for all types, which results in boxing and unboxing for arrays of primitive types.

Let’s look at an example showing the declaration and use of jagged arrays.

string[][] Address = new string[2][];  // A jagged array of strings

Address[0] = new string[1];

Address[1] = new string[2];

Address[0][0] = “Address [0,1]”;

Address[1][0] = “Address [1,0]”;

Address[1][1] = “Address [1,1]”;

for (int i =0; i <=1; i++) {

      for (int j = 0; j < Address[i].Length; j ++)



You can compare the efficiency of jagged versus multidimensional arrays by studying the MSIL code generated in each case. Notice how the following code that uses a multidimensional array results in a function call.

int [,] secondarr = new int[1, 2];

secondarr[0, 0] = 40;

The preceding code generates the following MSIL. Notice the function call.

IL_0029: ldc.i4.s   40

IL_002b: call instance void int32[0…,0…]::Set(int32,int32,int32)

The following code shows the MSIL generated for a jagged array. Note the MSIL stelem instruction which replaces the array element at a given index with the int32 value on the evaluation stack.

int [][] intarr = new int[1][];

intarr[0] = new int[2];

intarr[0][0] = 10;

The preceding code generates the following MSIL. Note the use of the stelem instruction.

IL_001c:  ldc.i4.s   10

IL_001e:  stelem.i4

Additional Considerations

When using arrays you should also consider the following:

  • Sorting. If you retrieve data from a database, see if you can presort it by using an ORDER BY clause in your query. If you need to use the sorted results from the database for additional searching and sorting of the subset of results, you may require sorting the arrays. You should always measure to find out which approach works better for your scenario: sorting, using SQL queries, or sorting using arrays in the business layer.
  • Avoid returning an Array from a property. Instead, consider using indexing properties.

EmployeeList l = FillList();

for (int i = 0; i < l.Length; i++) {

   if (l.All[i] == x){…}


In the preceding code, each time the property All is used, you might be creating and returning an array. If the calling code uses the property in a loop as shown in the preceding code, an array is created on each iteration of the loop.

In addition, if you return an array from a method, the resulting code is somewhat nonintuitive. A code example follows. In either case, document the details for your API.

// calling code:

if (l.GetAll()[i]== x) {…}

If you must return an array from a piece of code, consider returning a copy to prevent synchronization issues between clients.

  • In the following code example, each call to the myObj property creates a copy of the array. As a result, a copy of the array will be created each time the code DoSomething(obj.myObj[i]) is executed.

for (int i = 0; i < obj.myObj.Count; i++)


In our next article, we’ll look at the optimizing working with Collections.