The C# string.Intern
method optimizes string
memory and performance. It allows us to put strings in the runtime's shared string
pool.
We call IsInterned
to see if an interned string
exists. Most programs will not use Intern or IsInterned
. But it helps to know what they are.
The Intern static
method can improve performance of string
comparisons by more than two times. Intern puts strings in a common string
pool maintained by the .NET runtime.
string
pool is an optimization mainly for string
literals, which are strings that you place directly in your code.String
literals are surrounded by quotes. They are constant and immutable—meaning you can't change them.// Regular string literal. string s1 = "I'm a string literal."; // Const string literal. const string s2 = "I'm also a string literal."; // Verbatim string literal. string s3 = @"I'm a string literal with the verbatim syntax.";
You cannot change string
literals. However, you can reassign the variable that points to them. This changes the reference, not the value.
string
reference only. The actual data, the literals, are left alone.class Program { static void Main() { string s = "I'm a string literal."; s = "I'm another literal."; } }
Intern takes a string
you build up at runtime and basically turns it into a string
literal. This makes comparisons much faster.
string
is generated at runtime, so it is not from the internal string
pool. It is on the heap.string
created at runtime, and add it to the string
pool. Now it is similar to a string
literal.using System.Text; // Part 1: create string at runtime. string s1 = new StringBuilder().Append("cat").Append(" and dog").ToString(); // Part 2: get interned string added at runtime. string s2 = string.Intern(s1);
Equals
It is faster to compare interned strings. The method that implements string
comparisons with always checks references first. If the references are equal, the comparison succeeds.
Equals
method is how the == operator is implemented in .NET. The first part tests the references for equality.public static bool Equals(string a, string b) { return ((a == b) || (((a != null) && (b != null)) && EqualsHelper(a, b))); }
Here we test the performance of comparing strings that have been interned with string.Intern
. The tests were repeated 10 times and averaged.
string
literals against a string
that has not been interned.string
literals against a string
that had string.Intern
called upon it. We use interned strings.String.Intern
improves performance by more than 4 times when the string
comparison is always true.string.Intern
method only speeds things up when 2 strings are equal, and both are interned.using System; using System.Text; // Create string at runtime. StringBuilder b = new StringBuilder().Append("cat ").Append("and ").Append("dog"); // Get runtime string. string s1 = b.ToString(); // Get string pool reference to string. string s2 = string.Intern(s1); int m = 10000; for (int v = 0; v < 10; v++) { int d = 0; long t1 = Environment.TickCount; // Version 1: test regular string. for (int i = 0; i < m; i++) { for (int a = 0; a < m; a++) { if (s1 == "cat and rabbit") { d++; // false } if (s1 == "cat and dog") { d--; // true } } } long t2 = Environment.TickCount; // Version 2: test interned string. for (int i = 0; i < m; i++) { for (int a = 0; a < m; a++) { if (s2 == "cat and rabbit") { d++; // false } if (s2 == "cat and dog") { d--; // true } } } // Write results. long t3 = Environment.TickCount; Console.Write((t2 - t1)); Console.WriteLine("," + (t3 - t2)); }No string.Intern: 1540 ms With string.Intern: 736 ms [faster]
IsInterned
With string.IsInterned
, you can test whether a string
is present in the internal table, without adding it if it is not. It receives a string
reference and returns one too.
string
is found, that reference is returned. If no internal string
is present, a null
reference is returned.string
literal is tested. This reveals that string
literals are always present in the intern table.string
is not present in the intern table.IsInterned
will return null
in this case. It will not add the string
to the intern table.using System; class Program { static void Main() { // See if a string literal is interned. string value1 = "cat"; string value2 = string.IsInterned(value1); Console.WriteLine(value2); // See if a dynamically constructed string is interned. string value3 = "cat" + 1.ToString(); string value4 = string.IsInterned(value3); Console.WriteLine(value4 == null); } }cat True
In most programs, you do not need to use Intern or IsInterned
. But if you use the intern table in other places, you might want to use the string.IsInterned
method.
String.Intern
and IsInterned
act on the string
intern pool. Intern can make string
comparisons four or more times faster. The string
pool is an important optimization.