C# String Pooling

C# uses a concept called string pooling, where all literal strings are stored in a pool to reduce memory usage. When a literal string is used multiple times, C# reuses the same string from the pool instead of creating new instances. This mechanism optimizes memory usage and improves performance by avoiding the creation of redundant string objects.

Key Topics

1. String Pooling Concept

String pooling is an optimization technique used by the Common Language Runtime (CLR) to store only one instance of each unique literal string in a special memory area called the intern pool. When the same string literal appears multiple times in the code, the CLR reuses the existing instance from the pool instead of creating a new one.

Example: Basic String Pooling

string str1 = "Hello";
string str2 = "Hello";
Console.WriteLine(object.ReferenceEquals(str1, str2));  // Outputs: True

Output:

True

Code Explanation: Both str1 and str2 reference the same string instance in the intern pool, resulting in True when compared using ReferenceEquals().

2. Reference Equality of Literals

When string literals with the same value are declared, they point to the same memory location in the intern pool, ensuring reference equality.

Example: Comparing String Literals

string str1 = "Hello";
string str2 = "Hello";
Console.WriteLine(object.ReferenceEquals(str1, str2));  // Outputs: True

3. Runtime Strings and Interning

Strings created at runtime (not as literals) are not automatically interned. However, you can manually intern them using the String.Intern() method.

Example: Runtime String Interning

string str1 = new string(new char[] { 'H', 'e', 'l', 'l', 'o' });
string str2 = String.Intern(str1);
string str3 = "Hello";
Console.WriteLine(object.ReferenceEquals(str2, str3));  // Outputs: True

Output:

True

Code Explanation: The runtime-created string str1 is interned using String.Intern(), making it reference the same instance as the literal string str3, resulting in True when compared using ReferenceEquals().

4. Memory Efficiency

String pooling enhances memory efficiency by ensuring that identical strings share the same memory space, reducing the overall memory footprint of the application.

Example: Memory Usage Comparison

string[] literals = new string[1000];
string[] runtimeStrings = new string[1000];

for(int i = 0; i < 1000; i++)
{
    literals[i] = "Test"; // Interned
    runtimeStrings[i] = new string(new char[] { 'T', 'e', 's', 't' }); // Not interned
}

int internedReferences = 0;
for(int i = 0; i < 1000; i++)
{
    if(object.ReferenceEquals(literals[i], literals[0]))
        internedReferences++;
}

int nonInternedReferences = 0;
for(int i = 0; i < 1000; i++)
{
    if(object.ReferenceEquals(runtimeStrings[i], runtimeStrings[0]))
        nonInternedReferences++;
}

Console.WriteLine($"Interned References: {internedReferences}");      // Outputs: Interned References: 1000
Console.WriteLine($"Non-Interned References: {nonInternedReferences}"); // Outputs: Non-Interned References: 1

Output:

Interned References: 1000
Non-Interned References: 1

Code Explanation: The first loop initializes two arrays of strings: literals with string literals and runtimeStrings with runtime-created strings. The second loop checks reference equality for interned literals, which all point to the same instance, resulting in 1000 matches. The third loop checks reference equality for runtime strings, which are unique, resulting in only 1 match.

5. Using String.Intern() Method

The String.Intern() method can be used to intern runtime-created strings manually, ensuring that they reference the same instance in the intern pool if they have identical values.

Example: Manual String Interning

string runtimeStr = new string(new char[] { 'C', '#', ' ', 'I', 's', ' ', 'F', 'u', 'n' });
string internedStr = String.Intern(runtimeStr);
string literalStr = "C# Is Fun";
Console.WriteLine(object.ReferenceEquals(internedStr, literalStr));  // Outputs: True

Output:

True

Code Explanation: The runtime-created string runtimeStr is interned using String.Intern(), making it reference the same instance as the literal string literalStr, resulting in True when compared using ReferenceEquals().

Key Takeaways

  • String pooling is an automatic feature in C# that optimizes memory usage by reusing string instances.
  • String literals with the same value share the same reference in the intern pool.
  • Runtime-created strings are not interned by default but can be manually interned using String.Intern().
  • String pooling reduces memory usage and improves performance by avoiding duplicate string instances.
  • Understanding string pooling helps in writing memory-efficient and high-performance code.