c# - 连接或添加字符串但不使用 string.Format 时出现内存碎片?

标签 c# .net string string-concatenation memory-fragmentation

所以一位大学教授刚刚告诉我,在 C# 中对字符串使用连接(即当您使用加号运算符时)会产生内存碎片,我应该改用 string.Format

现在,我在 stack overflow 中搜索了很多,我发现很多关于性能的线程,其中连接字符串很容易胜出。 (其中一些包括 thisthisthis )

虽然我找不到谈论内存碎片的人。我使用 ILspy 打开了 .NET 的 string.Format,显然它使用了 string.Concat 方法相同的字符串生成器(如果我理解的话是 + 符号重载的内容)。事实上:它使用了 string.Concat 中的代码!

我找到了 this article from 2007但我怀疑它在今天(或永远!)是否准确。显然编译器足够聪明,今天可以避免这种情况,因为我似乎无法重现该问题。使用 string.format 和加号添加字符串最终在内部使用相同的代码。如前所述,string.Format 使用相同的代码 string.Concat 使用。

所以现在我开始怀疑他的说法。是真的吗?

最佳答案

So a professor in university just told me that using concatenation on strings in C# (i.e. when you use the plus sign operator) creates memory fragmentation, and that I should use string.Format instead.

不,您应该做的是进行用户研究,设置以用户为中心的现实世界性能指标,并根据这些指标衡量您的程序的性能。何时且仅当您发现性能问题,您应该使用适当的分析工具来确定性能问题的原因。如果原因是“内存碎片”,则通过确定“碎片”的原因和尝试实验来确定哪些技术可以减轻影响来解决这个问题。

性能不是通过“避免字符串连接”等“提示和技巧”实现的。性能是通过将工程学科应用于现实问题来实现的。

为了解决您更具体的问题:我从未听说过为了性能原因避免连接而支持格式化的建议。通常给出的建议是避免迭代串联,转而使用构建器。迭代连接在时间和空间上是二次的,会产生收集压力。构建器分配不必要的内存,但在典型场景中是线性的。两者都不会造成托管堆的碎片;迭代串联往往会产生连续 垃圾 block 。

由于托管堆的不必要的碎片,我遇到的性能问题恰好是一次;在 Roslyn 的早期版本中,我们有一个模式,我们会分配一个小的长生命周期对象,然后是一个小的短生命周期对象,然后是一个小的长生命周期对象......连续数十万次,最后得到最大碎片堆导致集合影响用户的性能问题;我们通过仔细测量相关场景中的性能来确定这一点,而不是通过坐在舒适的椅子上对代码进行临时分析。

通常的建议不是避免碎片化,而是避免压力。我们在 Roslyn 的设计过程中发现,一旦解决了上述分配模式问题,压力对 GC 性能的影响远大于碎片。

我对你的建议是要么向你的教授施压,要求他给出解释,要么找一位对绩效指标有更严格方法的教授。

现在,综上所述,您应该使用格式化而不是串联,但不是出于性能的原因。相反,是为了代码可读性、本地化性和类似的风格问题。格式字符串可以做成资源,可以本地化等等。

最后,我提醒您,如果您将字符串放在一起以构建诸如 SQL 查询或要提供给用户的 HTML block 之类的东西,那么您希望使用这些技巧。当您弄错这些字符串构建应用程序时,它们会产生严重的安全影响。使用专为构造这些对象而设计的库和工具,而不是使用字符串自己动手。

关于c# - 连接或添加字符串但不使用 string.Format 时出现内存碎片?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37146695/

相关文章:

c# - 哪个静态类先初始化?

C#:嵌套类的构造函数使 "inaccessible due to protection level"

java - 如何检查 String 是否仅包含 Java 中的 Date 格式?

c# - 无法加载文件或程序集 'Oracle.DataAccess, Version=4.112.4.0, Culture=neutral, PublicKeyToken=89b483f429c47342'

c# - 不一致 "Cross-thread operation not valid"异常

javascript - 如何将字符串转换为插值字符串?

javascript - 如何在javascript中使用toString(16)来获取以两个字符写入的字节

c# - 什么控制着C#中未等待的异步任务的数量?

c# - Ninject 和静态类 - 如何?

C#:基于非零的数组不符合 CLS