代码之家  ›  专栏  ›  技术社区  ›  Manos Ntoulias

包含私有调用的Java内联方法

  •  2
  • Manos Ntoulias  · 技术社区  · 7 年前

    假设jvm将b.foo()方法标识为hot,它会尝试内联它吗?因为如果这样做,调用指令b.bar()将在a.main方法中内联,这是被禁止的,因为bar是私有的。在这些情况下,JVM做什么?

    如有任何详细资料,我们将不胜感激。谢谢

    public class A {
    
        public static void main(String[] args)
        {
            B b = new B();
            for (int i=0; i<99999; i++)
                b.foo();
        }
    }
    
    class B {
    
        public void foo() {
            bar();
        }
    
        private void bar() { // do something. (is small method)
        }
    }
    

    编辑:我问是因为当我自己(在字节码中)尝试进行这种优化时,会得到一个验证错误,这是有意义的:

    java.lang.verifyerror:错误的invokeSpecial指令:当前类不能分配给引用类

    编辑2:

    public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=5, args_size=1
         0: new           #13                 // class B
         3: dup
         4: invokespecial #14                 // Method B."<init>":()V
         7: astore_1
         8: iconst_0
         9: istore_2
        10: iload_2
        11: ldc           #15                 // int 99999
        13: if_icmpge     30
        16: aload_1
        17: astore        4
        19: aload         4
        21: invokespecial #18                 // Method B.bar:()V // VERIFY ERROR HERE
        24: iinc          2, 1
        27: goto          10
        30: return
      StackMapTable: number_of_entries = 2
        frame_type = 253 /* append */
          offset_delta = 10
          locals = [ class B, int ]
        frame_type = 19 /* same */
      LineNumberTable:
        line 5: 0
        line 6: 8
        line 7: 16
        line 14: 19
        line 15: 24
        line 6: 24
        line 8: 30
    
    2 回复  |  直到 7 年前
        1
  •  4
  •   meriton    7 年前
    1. 一开始,有源代码
    2. Java编译器将其转换为字节码。
    3. JVM读取字节码,验证其完整性,并对其进行解释。“热点”(经常执行的代码块)的字节码及时编译到运行JVM的CPU的指令集中。

    在爪哇中,在步骤3中,大多数优化被推迟到JIT编译器,以从程序执行期间收集的统计数据中受益。这包括内衬。

    访问修饰符,如 private 在验证期间、解释字节码之前以及在对字节码进行JIT编译之前进行检查。由于访问修饰符已经被检查过,因此JIT完全不确定它们的存在,并且内联私有方法不会造成任何困难。

    顺便说一句,如果您想检查JIT的功能,可以使用Hotspot的 -XX:+PrintAssembly 将机器代码翻译回装配代码以供检查。

        2
  •  1
  •   Justin    7 年前

    在Java中,优化通常是在JVM级别完成的。在运行时,JVM执行一些“复杂”的分析,以确定要内联哪些方法。它可以在内联中具有攻击性,而Hotspot JVM实际上可以内联非最终方法。

    Java编译器几乎从不内联任何方法调用(JVM在运行时执行所有这些方法)。它们执行内联编译时间常量(例如,最终静态原语值)。但不是方法。

    更多资源:

    1. Article: The Java HotSpot Performance Engine: Method Inlining Example

    2. Wiki: Inlining in OpenJDK ,未完全填充,但包含指向有用讨论的链接。

    推荐文章