Origin:http://www.dotnet2themax.com/blogs/fbalena/PermaLink,guid,cecc8b4b-f362-4c59-95a1-fba055b50ec1.aspx
VB.NET and C# compilers manage string constants in a rather smart way: all strings with same value are stored in a common area known as string intern pool. The following code snippet shows this compiler feature in action:
' VB.NET
Dim s1 As String = "ABCDE"
Dim s2 As String = "ABC" & "DE"
' Prove that s1 and s2 point to the same element in the intern pool
Console.WriteLine(s1 Is s2) ' => True
// C#
string s1 = "ABCDE";
string s2 = "ABC" + "DE";
// Prove that s1 and s2 point to the same element in the intern pool
Console.WriteLine(String.ReferenceEquals(s1, s2)); // => True
This optimization technique doesn't really have any impact on the amount of memory used by most client applications, but it makes a difference if used inside types that are instantiated thousand times, as it often happens in server applications. The problem is, this optimization is applied only to string constants, not to strings built at runtime:
' VB.NET ...continuing previous example...
Dim s3 As String = "ABC"
s3 &= "DE"
' s1 and s3 contain the same value but point to a different string
Console.WriteLine(s1 = s3) ' => True
Console.WriteLine(s1 Is s3) ' => False
// C# ... continuing previous example...
string s3 = "ABC";
s3 += "DE";
Console.WriteLine(s1 == s3) // => True
Console.WriteLine(String.ReferenceEquals(s1, s3) // => False
Now, let's suppose you have a component in the data tier and this component contains the the connection string for the database. This connection string is read from somewhere - typically the configuration file - when it's time to open the connection, therefore the compiler can't store the string in the intern pool. If this component is instantiated N times, there will be N copies of the same string in memory, which clearly is a waste if the string is long and N is high. There are two ways to avoid this waste, depending on how the connection string can vary.
If the connection string is guaranteed to be the same for all the instances, then you can store it in a static variable (a Shared variable in VB), so that the string is shared among all the instances of the component. This is the simplest case and I assume you know how to implement it, so let's move to the more interesting situation.
If the connection string can vary - for example, if the data component can connect to two or more different databases or if the connection string can use different login information - you can't store it in a static field. In this case you can resort to a technique based on the String.Intern method. This method receives a string argument and searches the argument in the intern pool: if the search is successful, the method returns a pointer to the existing string in the pool; if the search fails, the method inserts the string in the pool and returns a pointer to the element just added. Here's how you might implement the ConnectionString property in the hypothetical data component to better leverage the intern pool:
' VB.NET
Dim m_ConnectionString As String
Property ConnectionString() As String
Get
Return m_ConnectionString
End Get
Set(ByVal Value As String)
m_ConnectionString = String.Intern(Value)
End Set
End Property
// C#
private string m_ConnectionString;
public string ConnectionString
{
get { return m_ConnectionString; }
set { m_ConnectionString = String.Intern(value);}
}
The first time a given value is assigned to the ConnectionString property, the search in the pool fails, the String.Intern method adds the string in the pool and returns a pointer to the new pool element. If the same connection string is eventualy assigned to a different instance of the data component, the String.Intern pool returns a pointer to the element already in the pool and doesn't create any duplicate. The total amount of memory that the application uses is reduced and so is the number of garbage collections that occur during the application's lifetime.