Java 静态调用比非静态调用更昂贵还是更便宜?

2023-12-02

是否有这样或那样的性能优势?它是编译器/VM 特定的吗?我正在使用热点。


四年后...

好吧,为了一劳永逸地解决这个问题,我编写了一个基准测试,它显示了不同类型的调用(虚拟、非虚拟、静态)之间的比较。

我运行了它关于ideone,这就是我得到的:

(迭代次数越多越好。)

    Success time: 3.12 memory: 320576 signal:0
  Name          |  Iterations
    VirtualTest |  128009996
 NonVirtualTest |  301765679
     StaticTest |  352298601
Done.

正如预期的那样,虚拟方法调用最慢,非虚拟方法调用更快,静态方法调用甚至更快。

我没想到的是差异如此明显:虚拟方法调用被测量为运行在少于一半非虚拟方法调用的速度,进而测量运行整个方法的速度慢 15%比静态调用。这就是这些测量结果所显示的;事实上,实际的差异必须稍微更加明显,因为对于每个虚拟、非虚拟和静态方法调用,我的基准测试代码都有一个额外的常量开销,即递增一个整数变量、检查布尔变量以及如果不为真则循环。

我想结果会因 CPU 和 JVM 的不同而不同,所以尝试一下,看看会得到什么:

import java.io.*;

class StaticVsInstanceBenchmark
{
    public static void main( String[] args ) throws Exception
    {
        StaticVsInstanceBenchmark program = new StaticVsInstanceBenchmark();
        program.run();
    }

    static final int DURATION = 1000;

    public void run() throws Exception
    {
        doBenchmark( new VirtualTest( new ClassWithVirtualMethod() ), 
                     new NonVirtualTest( new ClassWithNonVirtualMethod() ), 
                     new StaticTest() );
    }

    void doBenchmark( Test... tests ) throws Exception
    {
        System.out.println( "  Name          |  Iterations" );
        doBenchmark2( devNull, 1, tests ); //warmup
        doBenchmark2( System.out, DURATION, tests );
        System.out.println( "Done." );
    }

    void doBenchmark2( PrintStream printStream, int duration, Test[] tests ) throws Exception
    {
        for( Test test : tests )
        {
            long iterations = runTest( duration, test );
            printStream.printf( "%15s | %10d\n", test.getClass().getSimpleName(), iterations );
        }
    }

    long runTest( int duration, Test test ) throws Exception
    {
        test.terminate = false;
        test.count = 0;
        Thread thread = new Thread( test );
        thread.start();
        Thread.sleep( duration );
        test.terminate = true;
        thread.join();
        return test.count;
    }

    static abstract class Test implements Runnable
    {
        boolean terminate = false;
        long count = 0;
    }

    static class ClassWithStaticStuff
    {
        static int staticDummy;
        static void staticMethod() { staticDummy++; }
    }

    static class StaticTest extends Test
    {
        @Override
        public void run()
        {
            for( count = 0;  !terminate;  count++ )
            {
                ClassWithStaticStuff.staticMethod();
            }
        }
    }

    static class ClassWithVirtualMethod implements Runnable
    {
        int instanceDummy;
        @Override public void run() { instanceDummy++; }
    }

    static class VirtualTest extends Test
    {
        final Runnable runnable;

        VirtualTest( Runnable runnable )
        {
            this.runnable = runnable;
        }

        @Override
        public void run()
        {
            for( count = 0;  !terminate;  count++ )
            {
                runnable.run();
            }
        }
    }

    static class ClassWithNonVirtualMethod
    {
        int instanceDummy;
        final void nonVirtualMethod() { instanceDummy++; }
    }

    static class NonVirtualTest extends Test
    {
        final ClassWithNonVirtualMethod objectWithNonVirtualMethod;

        NonVirtualTest( ClassWithNonVirtualMethod objectWithNonVirtualMethod )
        {
            this.objectWithNonVirtualMethod = objectWithNonVirtualMethod;
        }

        @Override
        public void run()
        {
            for( count = 0;  !terminate;  count++ )
            {
                objectWithNonVirtualMethod.nonVirtualMethod();
            }
        }
    }

    static final PrintStream devNull = new PrintStream( new OutputStream() 
    {
        public void write(int b) {}
    } );
}

值得注意的是,这种性能差异仅适用于除了调用无参数方法之外不执行任何操作的代码。无论调用之间有什么其他代码,都会淡化差异,这包括参数传递。实际上,静态调用和非虚拟调用之间 15% 的差异可能是可以解释的in full事实上,this指针不必传递给静态方法。因此,只需要在调用之间使用相当少量的代码做一些琐碎的事情,就可以将不同类型的调用之间的差异稀释到没有任何净影响的程度。

此外,虚拟方法调用的存在是有原因的;它们确实有服务的目的,并且它们是使用底层硬件提供的最有效的手段来实现的。 (CPU 指令集。)如果您希望通过用非虚拟或静态调用替换它们来消除它们,您最终必须添加尽可能多的额外代码来模拟它们的功能,那么您产生的净开销是必然的不是更少,而是更多。很可能,很多,很多,难以想象的很多,更多。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java 静态调用比非静态调用更昂贵还是更便宜? 的相关文章

  • 如何将 JSpinner 的值设置为特定日期

    我有一个JSpinner我添加到JPanel我想将其时间设置为 GregorianCalendar calendar JSpinner spinner new JSpinner spinner setModel model pom add
  • 单元测试组合服务方法

    我正在为一个类编写 junit 单元测试 该类使用以下方法实现公开的接口 public Set
  • Quarkus 不以编程方式选择 bean

    我试图以编程方式选择 bean 但 quarkus 不会注入 bean 并引发异常 不支持吗 public enum ReportType ONE TWO Qualifier Retention RUNTIME Target METHOD
  • 如何提取文件 jre-9/lib/modules?

    In JRE 9 lib目录 至少在 Windows 上 有一个名为modules其大小约为107 MB 是否可以提取该文件或在其中列出 java 模块 我可以看到一个名为jmod可以在jdk 9 bin jmod exe 但那是为了阅读
  • GET 请求的 Spring 注解

    这两种spring GET方法有什么区别呢 哪一种是首选方法 Component Scope request Path public class TestComponent GET Path hello public String prin
  • 迁移到Java 9或更高版本时是否需要切换到模块?

    我们目前正在从 Java 8 迁移到 Java 11 但是 升级我们的服务并没有我们预期的那么痛苦 我们基本上只需要更改我们的版本号build gradle文件和服务都顺利启动并运行 我们升级了库以及使用这些库的 微 服务 到目前为止没有问
  • JTextField 和 JTextArea

    JTextField 和 JTextArea 有什么不同 是否可以在一个班级中使用这两个班级 总之 JTextField 是单行文本字段 而 JTextArea 可以跨越多行 文档中清楚地解释了这些差异 文本区 http docs orac
  • 在 Golang 中生成固定长度的随机十六进制字符串的有效方法?

    我需要生成很多固定长度的随机十六进制字符串 我找到这个解决方案golang中如何生成固定长度的随机字符串 https stackoverflow com a 31832326 710955 我正在做这样的事情 const letterByt
  • 使用 JSch 分别为各个提示提供输入

    问题是 SSH 连接需要在常规登录后提供另一个用户 ID 和密码信息 我正在使用 JSch 连接到远程服务器 它接受以下形式的输入InputStream 和这个InputStream只能通过一次 由于会话是交互式的 这会导致问题 我尝试将输
  • maven 无法下载 jacoco 0.7.10-SNAPSHOT jar

    我对此感到困惑 我的 pom xml 中有这个
  • 在 Java 中创建 T 的新实例

    在C 中 我们可以定义一个泛型class A
  • 正则表达式在 Velocity 模板中不起作用

    我在 Test java 中尝试过这个 String regex lt s br s s gt String test1 lt br gt System out println test replaceAll regex 但是当我在速度模板
  • Android volley使用RequestFuture.get()时出现超时异常

    在我的片段中 我尝试使用 TMDB 的开放电影数据库来获取有关 正在播放 电影的详细信息 如果我使用 RequestFuture get time TimeUnit 方法来执行此齐射请求 我总是会收到超时错误 如果我在 Safari 中手动
  • Java - JPanel 内有边距和 JTextArea

    我想创建这样的东西 主面板有其边距 x 并且 TextArea 位于该面板的中心 几乎填满了面板 底部是另一个具有自定义尺寸 高度 y 的面板 可以使用某些快捷方式将其切换为可见和不可见 底部面板有 FlowLayout 和几个元素 问题是
  • C# 编译器不会优化不必要的强制转换

    前几天 在写答案的时候这个问题 https stackoverflow com questions 2208315 why is any slower than contains在这里 关于溢出 我对 C 编译器感到有点惊讶 它没有按照我的
  • 如何检查日期字符串的有效性?

    在我的项目中 我需要检查日期字符串是否计算为正确的日期对象 我决定允许 yyyy MM dd 和日期格式 年 月 日 和 年 月 日 小时 分钟 我如何检查它们是否有效 我的代码为 1980 01 01 和一些奇怪的日期 如 3837 05
  • 在循环中按名称访问变量

    我正在开发一个 Android 项目 并且有很多可绘制对象 这些绘图的名称都类似于icon 0 png icon 1 png icon 100 png 我想将这些可绘制对象的所有资源 ID 添加到整数 ArrayList 中 对于那些不了解
  • Java:一个函数有多种返回类型...可以使用泛型吗?

    为了简单起见 我有一些程序 如下所示 public String fetchValueAsString String key public DateTime fetchValueAsDateTime String key 我想要类似的东西
  • Android Google 地图无法在当前主题中找到样式“mapViewStyle”

    添加谷歌地图视图时 我扩展了MapView 使用xml编辑器将其添加到活动中 并将我的谷歌地图api密钥手动添加到布局xml文件中 我的权限在清单文件中允许互联网 我想知道的是 在 xml 编辑器中 我收到错误 无法在当前主题中找到样式 m
  • 如何使用 Jest 从 ElasticSearch 获取索引列表

    我正在尝试使用 Jest 检索索引列表 但我只得到 Stats statistics new Stats Builder build result client execute statistics 如何从结果中检索索引列表 除了统计之外

随机推荐

  • 如何将变量的数字或值分配给 Fortran77/90 中的字符

    假设我使用实数变量 x 我想指定为一个字符 以便我可以根据 do 循环中 x 的值使用它来打印不同的文件名 我现在的代码是 program test print real 8 x character 40 chr x x 1 d0 do i
  • Firebase java对象序列化和继承[重复]

    这个问题在这里已经有答案了 它也序列化继承的属性吗 IgnoreExtraProperties public class Item extend BaseObservable private String foo public Item B
  • 无效的列名称“USER_SOURCE”

    我有一个存储过程 它以 xml 形式返回结果 Data输出参数 在xml代码中分配数据是 SELECT data SELECT DISTINCT CONVERT varchar 2 u USER SOURCE CONVERT varchar
  • 黑莓 - 自定义 BubbleChartField

    我需要开发一个应该显示气泡图的黑莓应用程序 如何实现这个目的的自定义控件 thanks UPDATE这是知识库如何 创建图形字段 你的问题应该更具体 更完整 好吧 只是为了给你指明方向 public class BubbleChart ex
  • Weka 从命令行预测到 CSV

    这与这个问题类似 Weka 对 CSV 的预测 但是从命令行 我有以下 Weka 命令 java Xmx10G weka classifiers meta FilteredClassifier t test data arff d pred
  • d3 v4:合并输入和更新选择以删除重复代码

    我明白那个merge可用于组合 d3 v4 中的输入和更新选择 如以下简单示例所示 https bl ocks org mbostock 3808218 我有一个散点图 其中多个变量显示在共享 x 轴上 用于下拉框选择的不同组 选择新组时
  • 即使每个更改的文件都与父文件之一一致,如何“git show”具有组合差异输出的合并提交?

    进行 简单 合并 没有冲突 后 git show通常只显示类似的内容 commit 0e1329e551a5700614a2a34d8101e92fd9f2cad6 HEAD master Merge fc17405 ee2de56 Aut
  • 在 Inno Setup 中使用 rundll32 或 dpinst 安装驱动程序?

    我正在尝试使用 Inno Setup 安装驱动程序 看起来有 至少 两种方法可以做到这一点 dpinst exe或运行rundll反对这 inf file 我知道有两个不同版本的 DPinst 适用于 x86 和 x64 根据操作系统的不同
  • 范围生成中“..”(双点)和“...”(三点)之间的区别?

    我刚刚开始学习 Ruby 和 Ruby on Rails 遇到了使用范围的验证代码 validates inclusion of age in gt 21 99 validates exclusion of age in gt 0 21 m
  • C++ 在什么条件下优化构造函数调用?

    我正在为矩阵算术编写一个类 我正在实现的一个功能是您可以 切片 一个矩阵并返回另一个矩阵 但这样做是为了使返回的矩阵引用父级的内存 如果您想要获取矩阵的一部分或将向量添加到列或类似的事情 这非常有用 但是 我想实现它 以便如果分配或复制返回
  • 为矩阵的每一行设置特定列的值

    我有一个矩阵A with m行 我想将每行的特定元素设置为 1 列索引因行而异 由列向量指定a with m值 也就是说 我想要A i a i 1 有没有一种快速的方法可以在Matlab中做到这一点 没有for循环 我用以下方法解决了这个问
  • Python urllib2.open 连接被对等错误重置

    我正在尝试使用 python 抓取页面 问题是 我不断收到 Errno54 连接被同行重置 当我运行此代码时出现错误 urllib2 urlopen http www bkstr com webapp wcs stores servlet
  • 计算两个经纬度点之间的距离? (半正矢公式)

    如何计算由纬度和经度指定的两点之间的距离 为了澄清起见 我想要以公里为单位的距离 这些点使用 WGS84 系统 我想了解可用方法的相对精度 This link可能对您有帮助 因为它详细介绍了半正矢公式来计算距离 Excerpt 该脚本 Ja
  • SQL Server 表填充源

    我有一个审计数据库 由其他人创建 有些东西正在用表大小数据填充它 这很有意义 因为它是审计数据库 SQL 服务器有太多的工作 我想知道审计表中填充了什么 有没有像 sys comments 之类的东西 它可以告诉我什么正在填充表 或者我是否
  • Google App Script 背景通过 HtmlService 透明

    我正在为 google 网站使用 google apps 脚本 并且我可以使用以下命令轻松创建透明背景UiApp createApplication setStyleAttribute background transparent 现在 我
  • 将 NuGet 包替换为本地 dll 文件

    我正在开发的项目依赖于 NuGet 包 包内的dll文件是在Release模式下编译的 因此使用调试器检查代码 这是我的目标 是不可能的 我想用我在调试模式下编译的文件替换 dll 文件 如果我通过 NuGet 删除包然后通过添加它Add
  • Paradox 如何管理 null 值和空值?

    我通过 Borland 数据库引擎 BDE 使用 Paradox 表 我无法领悟道路null and 空字符串值在字符串字段中处理 Paradox 数据类型 A 我的具体问题是如何确定字段值是否为空或空字符串 在数据库桌面工具中 它们似乎都
  • 如何在 Python 3 pyspark 中反转 RDD 中的键和值?

    这在 Python 2 7 中有效 但在 Python 3 5 中它返回 语法错误 语法无效 我不确定这是否与我在另一篇文章中读到的 元组解包 从 Python 3 中删除这一事实有关 或者是一个不同的问题 rddInverted rdd
  • MATLAB 的“fminsearch”与 Octave 的“fmincg”不同

    我试图在 MATLAB 和 Octave 中的两个函数之间获得简单优化问题的一致答案 这是我的代码 options optimset MaxIter 500 Display iter MaxFunEvals 1000 objFunc t l
  • Java 静态调用比非静态调用更昂贵还是更便宜?

    是否有这样或那样的性能优势 它是编译器 VM 特定的吗 我正在使用热点 四年后 好吧 为了一劳永逸地解决这个问题 我编写了一个基准测试 它显示了不同类型的调用 虚拟 非虚拟 静态 之间的比较 我运行了它关于ideone 这就是我得到的 迭代