You are wondering how efficiently C# uses memory and how you can improve the memory usage in your program by modifying the storage of large collections of data in your application. By using CLRProfiler, you can gauge memory and test the memory usage of classes and value types.
This C# performance article tests the memory usage of arrays. It measures structs and classes.

Tip: We measure with CLRProfiler on 32-bit Windows.

The program here has two classes that contain object references. The first class TestArray1 contains only three object references, for three arrays. The array variables such as string[] are actually only references and are lightweight. The second class TestArray2 contains an array of classes; each class in the array has the same three value types. The program tests three separate arrays of objects against an array of classes with those same values.
Program that measures memory [C#]
using System;
class TestArray1
{
public string[] _value1; // Array of string references
public int[] _value2; // Array of integers
public DateTime[] _value3; // Array of structs
}
class TestArray2
{
public TestClass1[] _class1; // Array of classes
}
class TestClass1
{
public string _value1; // String reference
public int _value2; // Integer
public DateTime _value3; // Struct
}
class Program
{
const int _constant = 10000000; // <-- Number of elements required
static void Main()
{
if (true) // <-- True will test the arrays, false will check the classes
{
//
// This tests the memory usage with separate arrays.
//
TestArray1 test1 = new TestArray1();
test1._value1 = new string[_constant]; // <-- Allocate each array
test1._value2 = new int[_constant];
test1._value3 = new DateTime[_constant];
}
else
{
//
// This tests the memory usage of array of classes.
//
TestArray2 test2 = new TestArray2();
test2._class1 = new TestClass1[_constant];
for (int i = 0; i < test2._class1.Length; i++)
{
test2._class1[i] = new TestClass1(); // <-- Allocate each class
}
}
}
}Notes. The value types stored in each class are a string reference, which actually stores no data unless assigned; an integer value, which contains storage for the value inline; and a DateTime struct, which also contains its storage inline.
Class Examples
The Main entry point. The Main method contains two paths, which you can change by turning the 'true' Boolean literal to 'false'. In the first path, the three arrays in TestArray1 are allocated with 10 million values each. In the second path, the TestArray2 class is allocated, and its array of TestClass1 references is allocated. Finally, its class references are allocated. In the end, both paths allocate the same values.
The CLRProfiler application is developed by Microsoft and is rough around the edges, but it provides an accurate look into your application's memory usage, although it does affect performance. When you download the CLRProfiler, extract it to your C:\ directory and then browser to the x86 folder, and double-click on CLRProfiler.exe.
Using the CLRProfiler dialog box. The profiler dialog box will appear at this point. Click on the "Start Application..." button and then select the Release binary for your program (such as ConsoleApplication461.exe) that is in the Visual Studio Projects directory.
Program will execute. Finally, your application will execute. If the program is too large or allocates too much, it will be very slow; you may need to reduce its allocations in your C# code first. Next, you will see the Summary dialog (shown at top of this article). Click on the buttons and explore the graphs and histograms.
MSDN referenceTaking screenshots. I usually just take screenshots of the charts instead of saving the files, because I have organization problems when working on the computer.
Here we look again at the example program and inspect the two snapshots from CLRProfiler I took when executing the programs in CLRProfiler. First, here is the benchmark for TestArray1 (which is in the first path of the Main entry point). Memory usage is 153 MB total: 76 MB for DateTime array; 38 MB for integer array; and 38 MB for all string references.

Next memory benchmark. Next we look at the memory usage from running the program in the second path in the Main entry point, which tests TestArray2. The memory usage here is much higher, because the values and references are not allocated in contiguous memory. Memory usage is 267 MB total: 229 MB for all class object data; 38 MB for all class references in the array.

Summary of benchmark results. By using separate arrays, which contain all their values and references to objects in continuous storage, the program saves over 100 MB. If you look at Task Manager when running these Release executables, the difference is greater. I am not certain why this occurs, but it also proves the massive memory efficiency gain.
Task manager measurement Program with three arrays: 40612 KB [smaller] Program with one array: 276936 KB

I consider object-oriented programming's greatest strength to be its separation of concerns and information hiding. The class type itself is not the key to OOP, but rather the barricading of outside accesses to discrete units of data and behavior. Therefore, if you change the internal storage of your class to use three arrays instead of a class array, you do not violate the principles of OOP.
Object-Oriented Programming BenefitsFactory design pattern. If your program uses an object such as Employee that is stored in an array, you can store the data in separate arrays and return a new object of type Employee that is constructed lazily. This is only useful when only one Employee object will be needed by the caller, however. It could lead to more problems.
Factory Pattern
We looked at how you can greatly decrease the memory usage of your C# programs by using arrays of value types instead of separate class instances, which allow more efficient data storage by the CLR. The program here with 10 million simple instances of three values was reduced by 114 MB or more. Finally, we discussed memory allocation in the C# language and the CLR, and mentioned the principles of object orientation and factory methods.
.NET Framework Info