c# - 使用 StringBuilder Remove 方法比在循环中创建新的 StringBuilder 方法更节省内存吗?

标签 c# memory-leaks garbage-collection stringbuilder

在 C# 中哪个内存效率更高:选项 #1 还是选项 #2?

public void TestStringBuilder()
{
    //potentially a collection with several hundred items:
    string[] outputStrings = new string[] { "test1", "test2", "test3" };

    //Option #1
    StringBuilder formattedOutput = new StringBuilder();
    foreach (string outputString in outputStrings)
    {
        formattedOutput.Append("prefix ");
        formattedOutput.Append(outputString);
        formattedOutput.Append(" postfix");

        string output = formattedOutput.ToString();
        ExistingOutputMethodThatOnlyTakesAString(output);

        //Clear existing string to make ready for next iteration:
        formattedOutput.Remove(0, output.Length);
    }

    //Option #2
    foreach (string outputString in outputStrings)
    {
        StringBuilder formattedOutputInsideALoop = new StringBuilder();

        formattedOutputInsideALoop.Append("prefix ");
        formattedOutputInsideALoop.Append(outputString);
        formattedOutputInsideALoop.Append(" postfix");

        ExistingOutputMethodThatOnlyTakesAString(
           formattedOutputInsideALoop.ToString());
    }
}

private void ExistingOutputMethodThatOnlyTakesAString(string output)
{
    //This method actually writes out to a file.
    System.Console.WriteLine(output);
}

最佳答案

有几个答案温和地建议我摆脱困境并自己弄清楚,所以下面是我的结果。我认为这种情绪通常与该网站的主旨背道而驰,但如果您希望做对某事,您不妨……:)

我修改了选项 #1 以利用 @Ty 建议使用 StringBuilder.Length = 0 而不是 Remove 方法。这使得两个选项的代码更加相似。现在的两个区别是 StringBuilder 的构造函数是在循环中还是在循环外,选项 #1 现在使用 Length 方法来清除 StringBuilder。这两个选项都设置为运行一个包含 100,000 个元素的 outputStrings 数组,以使垃圾收集器做一些工作。

几个答案提供了查看各种 PerfMon 计数器等的提示,并使用结果来选择一个选项。我做了一些研究,最终使用了我工作中使用的 Visual Studio Team Systems Developer 版本的内置 Performance Explorer。我找到了一个多部分系列的第二篇博客文章,解释了如何设置它 here .基本上,您连接一个单元测试以指向您要分析的代码;通过向导和一些配置;并启动单元测试分析。我启用了 .NET 对象分配和生命周期指标。很难为这个答案格式化的分析结果,所以我把它们放在最后。如果您将文本复制并粘贴到 Excel 中并稍微修改一下,它们将是可读的。

选项 #1 的内存效率最高,因为它使垃圾收集器做的工作少一点,并且它为 StringBuilder 对象分配的内存和实例比选项 #2 少一半。对于日常编码,选择选项 #2 非常合适。

如果您仍在阅读,我问这个问题是因为选项 #2 会使经验丰富的 C/C++ 开发人员的内存泄漏检测器变得弹道。如果在重新分配之前未释放 StringBuilder 实例,则会发生巨大的内存泄漏。当然,我们 C# 开发人员不担心这些事情(直到他们跳起来咬我们)。感谢大家!!


ClassName   Instances   TotalBytesAllocated Gen0_InstancesCollected Gen0BytesCollected  Gen1InstancesCollected  Gen1BytesCollected
=======Option #1                    
System.Text.StringBuilder   100,001 2,000,020   100,016 2,000,320   2   40
System.String   301,020 32,587,168  201,147 11,165,268  3   246
System.Char[]   200,000 8,977,780   200,022 8,979,678   2   90
System.String[] 1   400,016 26  1,512   0   0
System.Int32    100,000 1,200,000   100,061 1,200,732   2   24
System.Object[] 100,000 2,000,000   100,070 2,004,092   2   40
======Option #2                 
System.Text.StringBuilder   200,000 4,000,000   200,011 4,000,220   4   80
System.String   401,018 37,587,036  301,127 16,164,318  3   214
System.Char[]   200,000 9,377,780   200,024 9,379,768   0   0
System.String[] 1   400,016 20  1,208   0   0
System.Int32    100,000 1,200,000   100,051 1,200,612   1   12
System.Object[] 100,000 2,000,000   100,058 2,003,004   1   20

关于c# - 使用 StringBuilder Remove 方法比在循环中创建新的 StringBuilder 方法更节省内存吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/266923/

相关文章:

c# - 即使在 ProcessWindowStyle.Hidden 之后,控制台窗口仍然弹出;

c# - WPF TreeView 绑定(bind)多个子集合

swift - NSAsynchronousFetchRequest 可能的内存泄漏

python - Memoize Python 垃圾收集

c# - 使用 jquery ajax 在 aspx.cs 文件中调用 webmethod

c# - 在 Xamarin 中绑定(bind) iOS 委托(delegate)时出错

objective-c - 很难在哪里放置 CFRelease 调用

C# - 以编程方式尝试检查代码块中的内存泄漏的方法

java - GC 会在 Android 上自动处理/释放在 jni 中分配的内存吗?

python - 如何知道何时在 Python 中管理资源