当前位置: 首页 > 知识库问答 >
问题:

为什么传递两个字符串参数比一个列表参数更有效

蒋文光
2023-03-14

下面的代码分别调用两个简单的函数100亿次。

public class PerfTest {
    private static long l = 0;

    public static void main(String[] args) {
        List<String> list = Arrays.asList("a", "b");
        long time1 = System.currentTimeMillis();
        for (long i = 0; i < 1E10; i++) {
            func1("a", "b");
        }
        long time2 = System.currentTimeMillis();
        for (long i = 0; i < 1E10; i++) {
            func2(list);
        }
        System.out.println((time2 - time1) + "/" + (System.currentTimeMillis() - time2));
    }

    private static void func1(String s1, String s2) { l++; }
    private static void func2(List<String> sl) { l++; }
}

我的假设是这两个调用的性能几乎相同。如果有的话,我会猜到传递两个参数会比传递一个稍微慢一些。鉴于所有参数都是对象引用,我并不期望其中一个参数是列表这一事实会产生任何差异。

我运行了多次测试,一个典型的结果是“12781/30536”。换句话说,使用两个字符串的调用需要13秒,使用列表的调用需要30秒。

更新

这不是一个公平的测试,原因很多。然而,它确实演示了Java编译器的真实行为。请注意以下两个添加部分来演示这一点:

  • 向函数中添加表达式s1.getClass()sl.getClass()使两个函数调用perfom相同
  • 使用-xx:-TieredCompility运行测试还会使两个函数调用执行相同的操作

共有1个答案

颜霖
2023-03-14

基准是不公平的,然而,它揭示了一个有趣的影响。

正如Sotirios Delimanolis所注意到的,性能差异是因为func1是由HotSpot编译器内联的,而func2不是。原因是list类型的func2参数,该类在执行基准期间从未解析。

请注意,实际未使用List类:未调用列表方法,未声明List类型的字段,未进行类强制转换,也未执行通常导致类解析的其他操作。如果在代码中的任何位置添加list类的用法,则func2将内联。

影响编译策略的另一个因素是方法的简单性。它是如此的简单,以至于JVM已经决定在第1层(C1中编译它,没有进一步的优化)。如果它是用C2编译的,list类将被解析。尝试使用-xx:-TieredCompility运行,您将看到func2成功内联,并且执行速度与func1一样快。

手动编写逼真的微基准是一项非常困难的工作。有很多方面可能导致混乱的结果,例如内联、死代码消除、堆栈替换、概要文件污染、重新编译等等,这就是为什么强烈建议使用正确的基准测试工具,如JMH。一个手写的基准可以很容易地骗过JVM。特别是,真正的html" target="_blank">应用程序不太可能有带有从未使用过的类的方法。

 类似资料:
  • 问题内容: 我在网上找到了这段代码,其中有一部分我不理解。对于doInBackground方法,传递的参数为。有人可以告诉我这是什么意思吗?那是什么 问题答案: doInBackground(String… params) // params represents a vararg. new AsyncHttpPost().execute(s1,s2,s3); // pass strings to

  • 问题内容: 现状: 我有一个带有表的工作数据库,可以查询,插入,更新等。游标也连接到正确的数据库。 桌子: 问题: 当从表中查询数据时,我遇到了麻烦: 调试时,我看了cursor.execute()函数:将传递给: 哪里 被称为。我不确定转换器在做什么,但是结果是 。并将这些参数传递给execute函数,它将遇到以下错误: 错误的解决方法: 我有一个肮脏的解决方法,但对此不满意。在某些情况下可能不

  • 我有一个更新所有员工的方法,在服务层为每个单个员工调用该方法。 我必须优化代码,并用列表参数调用它一次。出于这个原因,我将id参数转换为list。 除了增强For循环和在每个员工上迭代之外,还有什么解决方案吗?

  • 问题内容: 我想将参数(即字符串)传递给Onclick函数。目前,我这样做: 例如,result.name等于字符串“ Add”。当我单击此按钮时,出现一个错误,提示未定义添加。由于此函数调用可以完美地与数字参数一起使用,因此我认为它与字符串中的符号“”有关。以前有人遇到过这个问题吗? 问题答案: 看起来您是从字符串构建DOM元素。您只需要在result.name周围添加一些引号即可: 您实际上应

  • 问题内容: 我有一个简单的疑问。如果有人帮助我,那就太好了。 我有两个字符串: 这两个值相等,但是如何在Java中比较它们呢?我们拥有并用于比较字符串alpha值,类似地,如何比较数字值。 问题答案: 这就对了。您可以使用方法将数字字符串转换为整数,该方法将返回类型。然后比较与相同。

  • 问题内容: 我正在将ajax发布到webmethod上,我可以在客户端(通过Firebug)看到请求的状态为200,但未达到我的webmethod中的停止点(webmethod的第一行)。json参数一切正常,但是通过反序列化json的方式,我不得不将其更改为字符串。 js: aspx: 问题答案: 您在jQuery JSON帖子中缺少内容类型: 请参阅本文。当我遇到类似的问题时,它对我很有帮助: