2010-08-13 73 views
9

对字符串进行子串处理是一种非常常见的字符串处理操作,但是我听说Java和.NET平台之间在性能/实现方面可能会有相当大的差异。具体我听说在Java中,java.lang.String报价常数时间操作为substring,但在.NET中,System.String报价线性性能Substring.NET和Java之间的子串操作性能比较

这些是真的吗?这可以在文档/源代码等确认吗?该实现是特定的还是由语言和/或平台指定的?每种方法的优缺点是什么?一个人从一个平台迁移到另一个平台应该怎样才能避免陷入任何性能缺陷?

+1

为什么不运行你自己的微型基准测试来测试这个?你能链接到说它有“糟糕”表现的来源吗? – Oded 2010-08-13 06:57:39

+0

@Oded:来源是丹尼陈的评论在这里http://stackoverflow.com/questions/3474254/how-to-make-a-first-letter-capital-in-c/3474263#3474263;老实说,如果'Substring'不是'O(1)'时空操作(比如Java),但是我会给他带来疑问的好处,因为我不知道.NET。 – polygenelubricants 2010-08-13 06:59:09

+1

这是什么意思“不良行为”?相对于什么?例如,与C++相比,.NET也有不好的表现。因此,我们应该放弃.NET吗? – 2010-08-13 07:07:35

回答

11

在.NET中,Substring是O(n),而不是Java的O(1)。这是因为在.NET中,String对象包含所有实际字符数据本身 - 所以取一个子字符串涉及复制新子字符串中的所有数据。在Java中,substring只需创建一个引用原始char数组的新对象,并使用不同的起始索引和长度。

有每一种方法的优点和缺点:

  • .NET的方法具有更好的高速缓存一致性,造成更少的对象,并且避免了一个小串防止收集了非常大的char[]是垃圾的情况。我相信在某些情况下,它可以使内部非常简单。
  • Java的方法使服用子非常有效的,而且很可能一些其它的操作也

有一个在我strings article更详细一点。

至于避免性能陷阱的一般问题,我想我应该有一个罐装答案准备好剪切和粘贴:确保你的体系结构是有效的,并以最可读的方式实现它。衡量性能,并优化你发现瓶颈的地方。


顺便说一句,这使得string很特别 - 它是唯一的非数组类型,其内存占用由实例相同CLR内变化。

对于小字符串,这是一个很大的胜利。足够糟糕的是,所有一个对象的开销,但是当涉及额外的数组时,单字符字符串在Java中可能需要大约36个字节。 (这是一个“手指在空中”的数字 - 我不记得确切的目标开销,它也将取决于你使用的虚拟机。)

2

使用反射,这是你的子串得到什么(的Int32,Int32)将

[SecuritySafeCritical, TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] 
public string Substring(int startIndex, int length) 
{ 
    return this.InternalSubStringWithChecks(startIndex, length, false); 
} 

,如果你继续在最后一次通话中去,是一个

internal static unsafe void wstrcpy(char* dmem, char* smem, int charCount) 

使用指针复制字符。 完整的代码实际上看起来很大,但你不会看到它有多快或多慢,直到你运行它并进行基准测试。

0

这真的取决于你的工作量。如果您正在循环并执行大量子字符串调用,那么您可能会遇到问题。对于你所指的SO帖子,我怀疑它永远是个问题。然而,用这种态度,你总是可以在“一千人的死亡裁员”的情况下结束。在SO张贴您参考,我们有以下几点:

String after = before.Substring(0, 1).ToUpper() + before.Substring(1); 

假设编译器不会做一些疯狂的优化,这将创造至少四个新的字符串(2个Substring电话,一个电话ToUpper和级联)。子串的实现与你期望的完全相同(字符串复制),但是上面分配的三个字符串很快就会变成垃圾。做这么多事情会造成不必要的记忆压力。我说“不必要”,因为你可能会想出更经济的解决方案,只需要多一点时间投资。

最后,分析器是你最好的朋友:)