所以基本上一般添加和处理字符串的方法正在被其他方式取代,因为它会导致混乱和资源浪费。我同意,但我想知道究竟是什么导致了这种资源浪费……正如这里所说。
'..并且您正在运行的实现没有用于处理字符串的复杂代码,您最终可能会做很多浪费的分配......' 链接 字符串缓冲区方法如何避免这种浪费......
我对此的解释来自 Java / .NET 背景,但是同样的逻辑也适用。
1.必须学习可变对象和不可变对象的概念...
Int32 / Integer 等对象是可变对象,这意味着它们可以在实例化后在其当前内存位置进行更改。这是因为无论对象的值如何,它在内存中的大小都不需要改变。
字符串是不可变的对象,这意味着一旦分配了它们,就不能在当前内存位置更改它们。这是因为字符串本质上可以是任意长度,因此,每次字符串更改长度时,系统/运行时都必须在内存中找到一个新位置来存储字符串。
2. 连接与 StringBuilder / StringBuffer
由于字符串是不可变的,因此每个连接都会强制重新分配内存。让我们假设以下示例使用 ASCII 编码(每个字符 1 个字节)
var message = "Hello World";
此时,系统已经分配了 11 个字节的内存来存储你的字符串。
message += "Hello Universe";
此时,系统必须为您的原始字符串再分配 14 个字节。您现有的 11 字节内存无法再存储您的新字符串!
为什么“处理字符串的复杂代码”(StringBuffer
/ StringBuilder
)可以帮助您!
每次将字符串附加到缓冲区/构建器时,它都会分配一次内存,并将指向该字符串的指针保存在内存中。下次分配字符串时,它会在新位置分配,而不会影响最后一个。一旦你完成了你的字符串的构建,缓冲区/构建器会将所有内容连接到一个字符串中,因此你的字符串分配会大大减少,因为你不是每次都在你的缓冲区/构建器中添加一些东西!
例子:
StringBuilder builder = new StringBuilder();
builder.Append("Hello World");
此时构建器已分配 11 个字节,并保持原样!
builder.Append("Hello Universe");
此时,构建器又分配了 14 个字节,保留最后一个字符串。
builder.ToString();
此时,构建器将内存中的所有字符串连接成一个字符串!
概括:
串联是一种资源浪费,因为:
系统/运行时必须清除旧的、取消引用的内存位置,这需要一些 CPU 时间。在 Java/.NET 中,它被称为垃圾收集。
每次重新分配内存都是一种浪费,直到垃圾收集器可以将其清理干净!
因此,串联会降低 CPU 和内存使用的性能!