Ela*_*lan 13 .net c# string substring
假设我有以下字符串:
string str1 = "Hello World!";
string str2 = str1.SubString(6, 5); // "World"
Run Code Online (Sandbox Code Playgroud)
我希望在上面的例子str2
中不复制"World",但只是最终成为一个新的字符串,指向相同的内存空间,只是它以6的偏移量和5的长度开始.
实际上我正在处理一些可能非常长的字符串,并且由于性能原因我对它在幕后的工作方式感兴趣.我不熟悉IL调查此事.
Eri*_*ert 20
正如其他人所说,CLR在进行子串操作时会复制.
正如您所注意到的,字符串肯定可以表示为具有长度的内部指针.这使得子串操作非常便宜.
还有一些方法可以使其他操作变得便宜.例如,通过将字符串表示为子串树,可以使字符串连接变得便宜.
在这两种情况下,这里发生的事情是操作的结果本身并不是"结果"本身,而是一个廉价的对象,它表示在需要时获得结果的能力.
细心的读者将会意识到这就是LINQ的工作原理.当我们说
var results = from c in customers where c.City == "London" select c.Name;
Run Code Online (Sandbox Code Playgroud)
"结果"并没有包含查询结果.此代码几乎立即返回; 结果包含一个表示查询的对象.只有在迭代查询时,搜索集合的昂贵机制才会启动.我们使用序列语义的monadic表示的功能将计算推迟到以后.
那么问题就变成"在字符串上做同样的事情是个好主意吗?" 答案是响亮的"不".我有很多痛苦的现实世界的实验.我曾经花了一个夏天重写VBScript编译器的字符串处理例程来存储字符串连接作为字符串连接操作的树; 只有当结果实际被用作字符串时才会发生连接.这是灾难性的; 跟踪所有字符串指针所需的额外时间和内存使99%的情况 - 有人做一些简单的小字符串操作来渲染网页 - 大约两倍的速度,同时大量加速微小的极少数使用天真字符串连接编写的页面.
.NET程序中的绝大多数现实字符串操作非常快; 它们编译成内存移动,在正常情况下,它们很好地保留在处理器缓存的内存块中,因此非常快.
此外,对字符串使用"内部指针"方法使垃圾收集器相当复杂; 采用这种方法似乎可能会使GC整体放缓,这对任何人都没有好处.您必须考虑变更影响的总成本,而不仅仅是它对某些狭隘场景的影响.
如果由于异常大的数据而有特定的性能需求,那么你应该考虑编写自己的专用字符串库,它使用像LINQ那样的"monadic"方法.您可以在内部将字符串表示为char数组,然后子字符串操作只是复制对数组的引用并更改开始和结束位置.
Ree*_*sey 15
这是一个新的字符串.
.NET中的字符串总是不可变的.每当通过包括Substring在内的方法生成新字符串时,它都会在内存中构造新字符串.您在.NET中共享对字符串中相同数据的引用的唯一情况是,您是否将字符串变量显式分配给另一个字符串(在其中复制引用),或者使用字符串常量(通常是实例).如果您知道您的字符串将与一个实习字符串(代码中的常量/字面值)共享一个值,您可以通过String.Intern检索"共享"副本.
这是一件好事,顺便说一句 - 为了做你所描述的,每个字符串都需要一个引用(字符串数据),以及一个偏移+长度.现在,他们只需要引用字符串数据.
在整个框架中,这将大大增加字符串的大小.
归档时间: |
|
查看次数: |
3066 次 |
最近记录: |