为何C#中使用StringBuilder时内存地址仍存在差异?
为什么StringBuilder操作后内存地址看起来不一样?
你犯了一个关键的测试错误:你没有检测StringBuilder内部缓冲区的内存地址,而是检测了每次调用ToString()生成的全新字符串的地址,这自然会导致两次地址不同。
问题根源拆解
StringBuilder.ToString()会创建新字符串
每次调用ToString(),都会将StringBuilder内部缓冲区的内容复制到一个全新的string实例中。由于C#的字符串是不可变的,这个新字符串会被分配到新的内存区域,所以每次的地址必然不同。你看到的地址是这些临时字符串的地址,而非StringBuilder内部存储字符的缓冲区地址。StringBuilder的可变性针对内部缓冲区
StringBuilder的高效性来自它内部维护的可变字符数组缓冲区:- 当调用
Append()时,如果现有缓冲区有足够空间,会直接在原有缓冲区追加内容,此时内部缓冲区的地址保持不变; - 如果追加内容超过缓冲区容量,StringBuilder会重新分配一块更大的缓冲区(此时内部缓冲区地址会变化),但这个变化你并没有检测到。
- 当调用
修正测试:检测StringBuilder内部缓冲区地址
如果你想验证StringBuilder内部缓冲区的地址变化,可以通过反射获取其内部缓冲区(注意:不同.NET版本的内部字段名可能略有差异,以下基于.NET Framework/.NET Core常见实现):
using System.Reflection; // ... 原有代码 ... Console.WriteLine("Using String Builder to (mutable string)"); StringBuilder str2 = new StringBuilder(); str2.Append("Interview"); Console.WriteLine("str2 text is:" + str2); // 获取内部缓冲区地址 var chunkCharsField = typeof(StringBuilder).GetField("_chunkChars", BindingFlags.NonPublic | BindingFlags.Instance); char[] internalBuffer = (char[])chunkCharsField.GetValue(str2); unsafe { fixed (char* pointer = internalBuffer) { Console.WriteLine("StringBuilder内部缓冲区地址: " + (int)pointer); } } str2.Append("Selection Process"); Console.WriteLine("str2 modified text is: " + str2); // 再次获取内部缓冲区地址 internalBuffer = (char[])chunkCharsField.GetValue(str2); unsafe { fixed (char* pointer = internalBuffer) { Console.WriteLine("StringBuilder修改后内部缓冲区地址: " + (int)pointer); } }
如果初始缓冲区容量足够容纳追加的内容,两次输出的内部缓冲区地址会相同;如果容量不足触发了扩容,地址才会变化。
总结
你的测试代码误将ToString()生成的新字符串地址当作StringBuilder的内存地址,这才导致结果与预期不符。StringBuilder的可变性体现在内部缓冲区的复用/扩容上,而非每次生成的字符串对象地址不变。
内容的提问来源于stack exchange,提问作者Malaka
相关产品推荐
相关产品推荐

