C# String Memory

by Sam Allen - Updated January 7, 2010

You want to measure the memory usage for the string type and string instances in the C# programming language and .NET Framework. The memory usage of strings is an implementation-specific detail of the string class, but because strings are so common, studying their memory usage can provide insights into the object model and the efficiency of character data. Here we measure the memory usage of the string type in a simple simulation, and then draw conclusions about the constant and varying memory usage of strings.

Each string object required a constant 20 bytes for the object data.
The buffer requires 2 bytes per character.                          
The memory usage estimate for string bytes is 20 + (2 * Length).    

String memory usage

First, this article targets the .NET Framework 3.5, although other versions are highly likely to have similar results. The program text runs a simulation where a varying number of strings of a certain length are allocated and placed in an array. The length of the array is changed to ensure the numbers remain constant for each individual string of a specific length. The program is based on a 32-bit Windows operating system, and is run in Release mode outside of the debugger. The results were that each string occupies 20 bytes of overhead and then 2 bytes for each character in its buffer.

--- Program that measures memory usage of strings (C#) ---

using System;

class Program
{
    static void Main()
    {
        // Loop through these sizes of string sets.
        // ... These are array lengths of string references.
        int[] sizes = { 0, 1, 100, 1000, 10000 };
        foreach (int size in sizes)
        {
            // Allocate the array of references.
            string[] array = new string[size];
            long b1 = GC.GetTotalMemory(true);
            // Each string is a fixed length.
            for (int i = 0; i < array.Length; i++)
            {
                array[i] = new string('a', 10);
            }
            long b2 = GC.GetTotalMemory(true);
            // Ensure the array is not optimized out of the program entirely.
            if (array.Length > 0)
            {
                array[0] = null;
            }
            // Write out statistics.
            Console.WriteLine("Count: {0} Memory: {1} Chars: {2}",
                size,
                b2 - b1,
                10 * size);
        }
        Console.ReadLine();
    }
}

--- Results for the program (Length = 10) ---

Count: 0 Memory: 0 Chars: 0
Count: 1 Memory: 40 Chars: 10
Count: 100 Memory: 4000 Chars: 1000
Count: 1000 Memory: 40012 Chars: 10000
Count: 10000 Memory: 400012 Chars: 100000

--- Results for different string length (Length = 20) ---

Count: 0 Memory: 0 Chars: 0
Count: 1 Memory: 60 Chars: 20
Count: 100 Memory: 6000 Chars: 2000
Count: 1000 Memory: 60000 Chars: 20000
Count: 10000 Memory: 600012 Chars: 200000

Memory usage in bytes. With each string having ten characters, one string will require 40 bytes, and 100 strings will require 4000 bytes. Thus, each string of ten characters is equal to 40 bytes constantly. With each string having twenty characters, one string will require 60 bytes, and this is also constant. Each character therefore occupies two bytes and the string object data overhead itself is 20 bytes on this 32-bit Windows system.

Additional explanation. This program uses the GC.GetTotalMemory method to acquire the memory usage of the managed heap. Each string is an object on the managed heap and a character buffer. The allocation of the array of string references in the program is allocated before the memory usage is measured, and therefore is not counted in the difference of byte readings. The program displays the number of string objects (Count); the memory is bytes (Memory); and the total number of characters in the string objects (Chars). The program was run a second time with the length of the strings being set to 20 instead of 10 to get more data with varying lengths.

StringBuilder memory usage

In this section, we mention that the StringBuilder type in the .NET Framework, which is a parallel to the string type but with different allocation behavior, can use less memory because it does not store separate object data if you combine many strings. You can sometimes use StringBuilder to transform many strings into a single string, allowing for fewer objects on the managed heap.

(See StringBuilder Memory Use.)

Summary

Here we looked at the memory usage of strings in the C# programming language and .NET Framework 3.5 targeting the 32-bit Windows operating system. The string type occupied a constant 20 bytes of overhead for each object, with an additional two bytes per character in its buffer. Strings are objects in the C# language and therefore each one will be managed by the garbage collector separately.

(Do not copy this page.)

Dot Net Perls | Search
Memory Usage | Array Memory Usage | Bool Array Usage and Allocation | Garbage Collection Visualizations | Memory Usage, Measuring Reference and Value Types | SQLite vs. SQLCE Memory Usage
C# | Array.FindIndex Method | File.Replace Method | Enum Flags Attribute Use | Any Method
© 2010 Sam Allen. All rights reserved.
Dot Net Perls | Sam Allen