C# 有没有办法减少大数组中新字符串的分配?

问题描述 投票:0回答:1

我正在尝试了解内存分配以及如何减少它们。

我创建了以下长列表进行测试

var list = new List<int>(Enumerable.Range(0, 1_000_000).ToArray());

然后我循环遍历它并打印了这样的字符串

for (var i = 0; i < list.Count; i++) 
{
    Console.WriteLine("Item # " + list[i]); 
}

上一个循环生成了超过 200 万个分配。我相信

"Item # " + list[i]
行产生了 200 万个分配。

** 问题 1** 在这种情况下为什么要分配 200 万个字符串?

list[i]
是否必须作为字符串存储在堆中,这是 1 次分配,然后是另一个分配中的组合字符串,因此每个循环 2 次分配?

下一步我考虑使用字符串生成器来减少分配

var builder = new StringBuilder();
for (var i = 0; i < list.Count; i++)
{
    builder.Append("Item # ");
    builder.Append(list[i]);

    Console.WriteLine(builder.ToString());
 
    builder.Clear();
}

上面的代码有100万个分配,是之前分配的一半。

但是,仍然有很多分配。

我知道字符串是 C# 中的不可变对象,每个字符串在堆中都有自己的分配。但是,有没有一种方法可以重用内存分配,以便我们可以创建 1 个字符串,然后在该循环内一遍又一遍地重用相同的分配?就我而言,一旦打印了字符串,我就不再需要它了。对我来说,重用相同的分配并更新它的值是安全的。

** 问题2** 是否可以重复使用内存分配来减少分配量?

** 问题 3** 我还可以尝试哪些其他技巧来改善我的循环?

c# memory memory-management
1个回答
0
投票

** 问题1** 为什么在这种情况下会分配200万个字符串? list[i] 是否必须作为字符串存储在堆中,这是 1 次分配,然后是另一个分配中的组合字符串,因此每个循环 2 次分配?

表演

"Item # " + list[i]

进行两次分配:它从

list[i]
整数创建一个字符串,然后通过将常量
"Item #"
与之前收到的中间值连接起来创建另一个字符串。

基于

StringBuilder
的版本消除了
list[i]
string
的转换,并将其直接写入其后备缓冲区。

**问题2**是否可以重复使用内存分配来减少分配量?

是的,这就是

StringBuilder
的作用。不过,只要你想取出一个
string
,就需要分配。

您可以通过分配单个字符数组来进一步重用内存使用情况,但随后您还必须处理内容的实际长度。

或者根本不分配并按照评论的建议使用

Console.Write

** 问题 3** 我还可以尝试哪些其他技巧来改进我的循环?

见上文。这取决于您想做什么。

© www.soinside.com 2019 - 2024. All rights reserved.