关于Unity C# 的string

 

关于Unity C# 的string

     我之前只知道 很多高级语言中关于字符串都有一个常量池,来保证只有一份(我记得lua语言中string就是一份)。 感兴趣的可以看看为什么众多语言都将字符串设计成不可变的?。       深入了解之后发现没有那么简单。

 

      下面截图是自己很low的测试, 发现有意思的现象。

关于Unity C# 的string

关于Unity C# 的string

关于Unity C# 的string

 

微软官方对字符串的文档描述:

https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/classes-and-structs/constants    ,下面的话解释了我上方第一个截图

关于Unity C# 的string

https://docs.microsoft.com/zh-cn/dotnet/api/system.string.intern?view=netcore-3.1            这个就是字符串常量池 , 要注意生命周期,而且gc基本不会回收!

关于Unity C# 的string

   当我看到后面的描述我有点懵的,字符串有多份相同的拷贝?常量池的作用呢?   字符串值相等(hash值一样而已),但是两个变量的引用不等?

关于Unity C# 的string

 

 

 

 

 

https://dailydotnettips.com/the-string-intern-pool/  

这个文章也解答了疑惑, String.intern方法 跟 StringBuilder的ToString 返回的string引用不同的原因是什么 。  

 

常量池副作用:

关于Unity C# 的string

关于Unity C# 的string关于Unity C# 的string

 

 

 

 

https://blog.jetbrains.com/dotnet/2015/02/12/string-interning-effective-memory-management-with-dotmemory/  

dotMemory提供String重复检查。其背后的思想很简单:它会自动检查内存中具有相同值的字符串对象。打开内存快照后,您将看到以下字符串的列表:

关于Unity C# 的string

因为原生的 interned 池子存在一个相当严重的缺点–interned字符串将“永远”保留在内存中(或者,更正确的说,它们将在AppDomain的生存期内持续存在,因为内部缓冲池将存储对字符串的引用,即使不再需要它们)。

文章中作者提出一个方式开发者自己维护一个池子

Local Intern Pool

最简单的(尽管远非最佳)实现可能如下所示:

关于Unity C# 的string

处理算法也会有所变化:

关于Unity C# 的string

在这种情况下,ProcessLogFile完成工作后,将在下一次垃圾回收时从内存中删除

            谈论可能的改进–例如,使用HashSet代替LocalPool的字典,更灵活的池寿命管理。另一个可能的改进–如果已处理的字符串数量巨大,则用于缓存(LRU,MRU)的相同技术。

 

 

 

 

探索内存分配和字符串

https://blog.maartenballiauw.be/post/2016/11/15/exploring-memory-allocation-and-strings.html

文中提到的 ,说.Net垃圾回收快,  但是Unity不是的,unity的gc算法不是基于代的!

关于Unity C# 的string

       快速注:这两个使用谁比较好?""string.Empty?根据我们到目前为止所学到的知识"",它会被扣留,这意味着它只会在内存中存储一次,对吗?对!但是有一个缺点:每次使用时"",都会检查内部池,这会花费一些宝贵的CPU时间。如果使用string.Empty,则将传递对象引用,这意味着不会分配额外的内存,也不会浪费额外的CPU周期检查内部缓冲池

根据经验,请记住以下几点:

  • 如果应用程序具有很多长寿命的字符串,但没有大量的唯一字符串,则实习可以提高内存效率。
  • 如果应用程序中有很多寿命很长的字符串,但是它们几乎都是截然不同的值,那么字符串实习不会带来任何好处,因为无论如何都必须存储字符串。另外,它可能会耗尽内存...
  • 如果应用程序有很多短命的字符串,请相信垃圾回收器可以快速有效地完成其工作。   不适用unity
  • 如有疑问,请测量。使用内存分析器来检测字符串重复项,并分析它们来自何处以及如何对其进行优化。请当心您可能将字符串视为潜在的内存问题,但它们很可能不是

 

 

 

 

String VS StringBuilder

https://docs.microsoft.com/en-us/dotnet/api/system.text.stringbuilder?view=netcore-3.1

重要

         尽管StringBuilder类通常提供比String类更好的性能,但无论何时要操作字符串,都不应自动将String替换为StringBuilder。性能取决于字符串的大小,为新字符串分配的内存量,您的应用在其上执行的系统以及操作的类型。您应该准备测试您的应用程序,以确定StringBuilder是否确实在性能上有显着提高。

考虑在以下情况下使用String类:

  • 当您的应用程序将对字符串进行的更改次数很少时。在这些情况下,与String相比,StringBuilder的性能改进可能微不足道,甚至没有。
  • 当您执行固定数量的串联操作时,尤其是使用字符串文字时。在这种情况下,编译器可能会将串联操作组合为单个操作。
  • 当您在构建字符串时必须执行大量搜索操作时。该StringBuilder的类缺乏搜索方法,如IndexOfStartsWith。您必须将StringBuilder对象转换为String才能执行这些操作,这会抵消使用StringBuilder带来的性能优势。有关更多信息,请参见在StringBuilder对象中搜索文本部分。

考虑在以下情况下使用StringBuilder类:

  • 如果您希望应用程序在设计时对字符串进行未知数量的更改(例如,当您使用循环连接包含用户输入的随机数量的字符串时)。
  • 当您期望您的应用对字符串进行大量更改时。

StringBuilder对象 的默认容量为16个字符