字符串池:“Te”+“st”比“Test”快?

2024-03-17

我正在尝试一些有关字符串池的性能基准。然而,结果并不令人期待。

我做了3个静态方法

  • Perform0() 方法...每次都会创建一个新对象
  • Perform1() 方法...字符串文字“Test”
  • Perform2()方法...字符串常量表达式“Te”+“st”

我的期望是(1.最快 -> 3.最慢)

  1. 由于字符串池而“测试”
  2. “Te”+“st”,因为字符串池,但比 1 慢一点,因为 + 运算符
  3. new String(..) 因为没有字符串池。

但基准测试显示“测试”比“测试”稍快。

new String(): 141677000 ns 
"Test"      : 1148000 ns 
"Te"+"st"   : 1059000 ns

new String(): 141253000 ns
"Test"      : 1177000 ns
"Te"+"st"   : 1089000 ns

new String(): 142307000 ns
"Test"      : 1878000 ns
"Te"+"st"   : 1082000 ns

new String(): 142127000 ns
"Test"      : 1155000 ns
"Te"+"st"   : 1078000 ns
...

这是代码:

import java.util.concurrent.TimeUnit;


public class StringPoolPerformance {

    public static long perform0() {
        long start = System.nanoTime();
        for (int i=0; i<1000000; i++) {
            String str = new String("Test");
        }
        return System.nanoTime()-start;
    }

    public static long perform1() {
        long start = System.nanoTime();
        for (int i=0; i<1000000; i++) {
            String str = "Test";
        }
        return System.nanoTime()-start;
    }

    public static long perform2() {
        long start = System.nanoTime();
        for (int i=0; i<1000000; i++) {
            String str = "Te"+"st";
        }
        return System.nanoTime()-start;
    }

    public static void main(String[] args) {
        long time0=0, time1=0, time2=0;
        for (int i=0; i<100; i++) {
            // result
            time0 += perform0();
            time1 += perform1();
            time2 += perform2();
        }

        System.out.println("new String(): " +  time0 + " ns");
        System.out.println("\"Test\"      : " + time1 + " ns");
        System.out.println("\"Te\"+\"st\"   : " + time2 + " ns");
    }
}

有人可以解释为什么“Te”+“st”比“Test”执行得更快吗? JVM在这里做了一些优化吗?谢谢。


"Te" + "st"是编译器时常量表达式,因此将在运行时表现没有什么不同而不是简单地"Test"。任何性能影响都将发生在尝试编译它时,而不是尝试运行它时。

通过使用反汇编编译的基准类可以轻松证明这一点javap -c StringPoolPerformance:

public static long perform1();
  Code:
...
   7:   ldc #3; //int 1000000
   9:   if_icmpge   21
   12:  ldc #5; //String Test
   14:  astore_3
   15:  iinc    2, 1
...

public static long perform2();
  Code:
...
   7:   ldc #3; //int 1000000
   9:   if_icmpge   21
   12:  ldc #5; //String Test
   14:  astore_3
   15:  iinc    2, 1
...

这些方法的字节码完全相同!这是由Java 语言规范,15.18.1 http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.18.1:

除非表达式是编译时常量表达式(第 15.28 节),否则 String 对象是新创建的(第 12.5 节)。

您遇到的基准差异可能是由于典型的可变性或因为您的基准并不完美。看这个问题:如何用 Java 编写正确的微基准测试? https://stackoverflow.com/questions/504103/how-do-i-write-a-correct-micro-benchmark-in-java

您违反的一些值得注意的规则:

  1. 您不会丢弃测试内核“预热”迭代的结果。
  2. 您没有启用 GC 日志记录(特别是当perform1() is always在创建一百万个对象的测试之后立即运行)。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

字符串池:“Te”+“st”比“Test”快? 的相关文章

  • JavaEE 8 教程,在 hello1 项目上部署失败

    我正在尝试学习 Java EE 8 我遵循了官方指南https javaee github io tutorial https javaee github io tutorial 但我有这个问题 cargo maven2 plugin 1
  • 有效地查找正则表达式的所有重叠匹配项

    这是后续与 java 正则表达式匹配的所有重叠子字符串 https stackoverflow com q 11303309 244526 有没有办法让这段代码更快 public static void allMatches String
  • 使用 jdbc 程序连接到 Open Office odb 文件

    我编写了以下代码来连接到 OpenOffice db String db C Documents and Settings hkonakanchi Desktop Test odb Class forName org hsqldb jdbc
  • java“void”和“非void”构造函数

    我用 java 编写了这个简单的类 只是为了测试它的一些功能 public class class1 public static Integer value 0 public class1 da public int da class1 v
  • firestore快照监听器生命周期和定价之间有什么关系?

    在我的活动中 我有一个字符串列表 这些字符串表示我想要附加快照侦听器的 Firestore 文档 我使用 Acivity ModelView 存储库结构 在活动的 onCreate 中 我向 ViewModelProvider 询问适当的
  • 如何在 PHP 中修剪定界文档(长字符串)中的每一行

    我正在创建一个 PHP 函数 可以修剪长字符串中的每一行 例如
  • 业务代表与服务定位器

    Business Delegate 和 Service Locator 之间有什么区别 两者都负责封装查找和创建机制 如果 Business Delegate 使用 Service Locator 来隐藏查找和创建机制 那么 Busines
  • 基本 C++ 文本对齐

    我正在尝试编写一个程序 该程序从文件中获取输入行并使其恰好为 80 个字符 假设输入行始终小于 80 然后打印该行 这是通过在以下标点符号后添加最多两个空格来完成的 如果一行少于 41 个字符 则不加修改地打印 如果该行仍然不是 80 个字
  • getClassLoader().getResource() 返回 null

    我有这个测试应用程序 import java applet import java awt import java net URL public class Test extends Applet public void init URL
  • 会话 bean 中的 EntityManager 异常处理

    我有一个托管无状态会话 bean 其中注入了 EntityManager em 我想做的是拥有一个具有唯一列的数据库表 然后我运行一些尝试插入实体的算法 但是 如果实体存在 它将更新它或跳过它 我想要这样的东西 try em persist
  • JSP 标签+ scriptlet。如何启用脚本?

    我有一个使用标签模板的页面 我的 web xml 非常基本 我只是想在页面中运行一些代码 不 我对标签或其他替代品不感兴趣 我想使用不好的做法 scriptlet 哈哈 到目前为止 我收到了 HTTP ERROR 500 错误 Script
  • Vertx HttpClient getNow 不工作

    我的 vertx HttpClient 有问题 下面的代码显示使用 vertx 和纯 java 测试 GET Vertx vertx Vertx vertx HttpClientOptions options new HttpClientO
  • 您能让 Tomcat 6 stdout.log 文件表现得像 log4j DailyRollingFileAppender 吗?

    我们使用的是 Tomcat 6 的 Windows 安装 默认情况下 我们应用程序的 log4j 输出将转到 catalina base logs stdout log 文件 该日志文件仅在我们重新启动 Tomcat 时滚动 并且文件名始终
  • 使用外部硬盘写入和存储 mysql 数据库

    我已经设置了 mysql 数据库在我的 Mac 上使用 java 和 eclipse 运行 它运行得很好 但现在我将生成大约 43 亿行数据 这将占用大约 64GB 的数据 我存储了大量的密钥和加密值 我有一个 1TB 外部我想用作存储位置
  • 通用 JSF 实体转换器[重复]

    这个问题在这里已经有答案了 我正在编写我的第一个 Java EE 6 Web 应用程序作为学习练习 我没有使用框架 只是使用 JPA 2 0 EJB 3 1 和 JSF 2 0 我有一个自定义转换器 用于将存储在 SelectOne 组件中
  • 嵌入式 tomcat 7 servlet 3.0 注释不起作用

    我有一个精简的测试项目 其中包含 Servlet 版本 3 0 用注释声明 如下所示 WebServlet test public class TestServlet extends HttpServlet private static f
  • 字节码和位码有什么区别[重复]

    这个问题在这里已经有答案了 可能的重复 LLVM 和 java 字节码有什么区别 https stackoverflow com questions 454720 what are the differences between llvm
  • 将字符串中的字符向左移动

    我是 Stack Overflow 的新手 有一道编程课的实验室问题一直困扰着我 该问题要求我们将字符串 s 的元素向左移动 k 次 例如 如果输入是 Hello World 和3 它将输出 lo WorldHel 对于非常大的 k 值 它
  • Java SE + Spring Data + Hibernate

    我正在尝试使用 Spring Data Hibernate 启动 Java SE 应用程序 并且到目前为止已经完成了以下操作 配置文件 Configuration PropertySource classpath hibernate pro
  • Java的hashCode可以为不同的字符串产生相同的值吗?

    使用java的哈希码函数是否可以为不同的字符串提供相同的哈希码 或者如果可能的话 其可能性的 是多少 Java 哈希码是 32 位 它散列的可能字符串的数量是无限的 所以是的 会发生冲突 百分比是没有意义的 项目 字符串 的数量是无限的 而

随机推荐