有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

子串运行性能比较。NET和Java

获取字符串的子字符串是一种非常常见的字符串操作,但我听说Java和Java在性能/实现方面可能有很大的差异。NET平台。具体地说,我听说在Java中,java.lang.Stringsubstring提供了常量时间操作,但是在。NET提供了线性性能Substring

真的是这样吗?能否在文档/源代码等中确认这一点?这个实现是特定的,还是由语言和/或平台指定的?每种方法的优缺点是什么?从一个平台迁移到另一个平台的人应该寻找什么来避免陷入性能陷阱


共 (4) 个答案

  1. # 1 楼答案

    这取决于你的工作量。如果你正在循环并进行大量的子串调用,那么你可能会遇到问题。对于你所指的SO帖子,我怀疑这是否会成为一个问题。然而,有了这种态度,你总是会陷入“被千张剪纸压死”的境地。在您提到的SO帖子中,我们有以下内容:

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

    假设编译器没有进行一些疯狂的优化,这将创建至少四个新字符串(2Substring调用、一个ToUpper调用和串联)。子字符串的实现完全符合您的预期(字符串复制),但上面分配的三个字符串将很快变成垃圾。这样做会造成不必要的内存压力。我说“不必要”是因为你可能只需要多花一点时间就能想出一个更经济的解决方案

    最后,探查器是您最好的朋友:)

  2. # 2 楼答案

    根据这一点,并不是真的: C# Substring

  3. # 3 楼答案

    使用reflector这是您从子字符串(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)
    

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

  4. # 4 楼答案

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

    每种方法都有利弊:

    • 。NET的方法具有更好的缓存一致性,创建更少的对象2,并避免了一个小的子字符串阻止对非常大的char[]进行垃圾收集的情况。我相信在某些情况下,它在内部也可以使互操作变得非常简单
    • Java的方法使得获取子字符串非常有效,可能还有其他一些操作

    在我的strings article中有更多的细节

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


    顺便说一句,这使得string非常特别——它是唯一一种内存占用在同一CLR中因实例而异的非数组类型

    2对于小琴弦来说,这是一个巨大的胜利。一个对象的所有开销已经够糟糕的了,但是如果还涉及一个额外的数组,在Java中一个字符串可能需要36字节左右。(这是一个“悬而未决”的数字——我记不起具体的对象开销。这还取决于您使用的虚拟机。)