关于Unity C# 的string
我之前只知道 很多高级语言中关于字符串都有一个常量池,来保证只有一份(我记得lua语言中string就是一份)。 感兴趣的可以看看为什么众多语言都将字符串设计成不可变的?。 深入了解之后发现没有那么简单。
下面截图是自己很low的测试, 发现有意思的现象。
微软官方对字符串的文档描述:
https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/classes-and-structs/constants ,下面的话解释了我上方第一个截图
https://docs.microsoft.com/zh-cn/dotnet/api/system.string.intern?view=netcore-3.1 这个就是字符串常量池 , 要注意生命周期,而且gc基本不会回收!
当我看到后面的描述我有点懵的,字符串有多份相同的拷贝?常量池的作用呢? 字符串值相等(hash值一样而已),但是两个变量的引用不等?
https://dailydotnettips.com/the-string-intern-pool/
这个文章也解答了疑惑, String.intern方法 跟 StringBuilder的ToString 返回的string引用不同的原因是什么 。
常量池副作用:
dotMemory提供String重复检查。其背后的思想很简单:它会自动检查内存中具有相同值的字符串对象。打开内存快照后,您将看到以下字符串的列表:
因为原生的 interned 池子存在一个相当严重的缺点–interned字符串将“永远”保留在内存中(或者,更正确的说,它们将在AppDomain的生存期内持续存在,因为内部缓冲池将存储对字符串的引用,即使不再需要它们)。
文章中作者提出一个方式开发者自己维护一个池子
Local Intern Pool
最简单的(尽管远非最佳)实现可能如下所示:
处理算法也会有所变化:
在这种情况下,ProcessLogFile完成工作后,将在下一次垃圾回收时从内存中删除池。
谈论可能的改进–例如,使用HashSet代替LocalPool的字典,更灵活的池寿命管理。另一个可能的改进–如果已处理的字符串数量巨大,则用于缓存(LRU,MRU)的相同技术。
探索内存分配和字符串
https://blog.maartenballiauw.be/post/2016/11/15/exploring-memory-allocation-and-strings.html
文中提到的 ,说.Net垃圾回收快, 但是Unity不是的,unity的gc算法不是基于代的!
快速注:这两个使用谁比较好?:""
或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的类缺乏搜索方法,如
IndexOf
或StartsWith
。您必须将StringBuilder对象转换为String才能执行这些操作,这会抵消使用StringBuilder带来的性能优势。有关更多信息,请参见在StringBuilder对象中搜索文本部分。
考虑在以下情况下使用StringBuilder类:
- 如果您希望应用程序在设计时对字符串进行未知数量的更改(例如,当您使用循环连接包含用户输入的随机数量的字符串时)。
- 当您期望您的应用对字符串进行大量更改时。
StringBuilder对象 的默认容量为16个字符
来源:oschina
链接:https://my.oschina.net/u/4418236/blog/4274826