JIT 编译的代码在哪里?

2022-01-16 00:00:00 jvm jit java

所以我有这个方法,用Java写的:

So I have this method, written in Java:

public void myMethod(int y){
    int x = 5 + y;
    doSomething(x);
}

假设我的应用程序调用了很多次..

And assume my application calls this a lot of times..

在 Java 虚拟机上运行此方法的编译代码时,JVM 将首先解释该方法.然后过了一段时间,如果我理解正确,它将决定将其编译为机器语言.

When running the compiled code for this method on Java Virtual Machine, JVM will first interpret the method. Then after some time it will decide to compile it to machine language if I understand correctly.

此时,

会被内存中的机器码覆盖吗?如果它被覆盖,大小差异的问题将如何解决?如果将其写入内存中的其他位置,加载到内存中的字节码是否会被释放?还有,如果字节码和jit编译的代码都在内存中,当应用再次点击这个方法时,JVM如何决定执行jit编译的代码而不是字节码?

Will it be overwritten by the machine code in the memory? If it is overwritten, how will the issue of the size difference solved? If it is written to some other place in memory, will the bytecode loaded into memory freed or not? And also, if both bytecode and the jit compiled code is in the memory, when the application hits this method again, how does JVM decide to execute the jit compiled code instead of byte code?

推荐答案

HotSpot JVM 有一个 Method 结构.它包含永远不会被覆盖的方法字节码和 指向已编译代码的指针,在编译方法之前最初为 NULL.

HotSpot JVM has a Method structure in Metaspace (or PermGen in earlier versions). It contains method bytecode which is never overwritten and a pointer to compiled code, initially NULL until the method is compiled.

一个方法可能有多个入口点:

A method may have multiple entry points:

  • _i2i_entry - 指向字节码解释器的指针.
  • _code->entry_point() - JIT 编译代码的入口点.编译后的方法驻留在 CodeCache - 本机内存的特殊区域,用于 VM 动态生成的代码.
  • i2cc2i 适配器从解释器调用编译后的代码,反之亦然.需要这些适配器,因为解释方法和编译方法具有不同的调用约定(参数传递方式、帧构造方式等)
  • _i2i_entry - a pointer to the bytecode interpreter.
  • _code->entry_point() - an entry point to the JIT-compiled code. Compiled methods reside in CodeCache - the special region of native memory for the VM dynamically generated code.
  • i2c and c2i adapters to call the compiled code from interpreter and vice versa. These adapters are needed, because the interpreted methods and compiled methods have different calling convention (the way how arguments are passed, how frames are constructed etc.)

编译的方法可能有不常见的陷阱,在极少数情况下会退回到解释器.此外,Java 方法可以多次动态重新编译,因此 JVM 无法丢弃原始字节码.无论如何释放它是没有意义的,因为字节码通常比编译后的代码小得多.

A compiled method can have uncommon traps that fall back to interpreter in some rare cases. Furthermore, a Java method can be dynamically recompiled multiple times, so JVM cannot throw away the original bytecode. There is no sense to free it anyway, because the bytecode is usually much smaller than the compiled code.

相关文章