9

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..

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.

At this point,

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?

Koray Tugay
  • 22,894
  • 45
  • 188
  • 319
  • I got the idea that this sort of thing would depend on whether you are running on a Windows machine or, say, on a RAM-starved microcontroller. In other words, platform dependent, no? – Ghostkeeper Jan 24 '15 at 13:43
  • 2
    Answer 1: Why do you care? Answer 2: The JVM keeps the JITCed code for each method in C heap, linked to via tables in the internal representation of the class object. The code is only deleted when the JVM ends or in the rare case that the class is "unloaded". It's all managed by suitable magic. – Hot Licks Jan 24 '15 at 14:06
  • 1
    The "C heap" is really a misnomer here - if it refers to memory obtained using calls to malloc (which may or may not be page-aligned) the corresponding pages would have to be marked as executable. More likely, the JIT allocates memory for generated code using mmap, VirtualAlloc and the like. – Martin Törnwall Jan 24 '15 at 14:44
  • The answer is implementation defined. – davmac Jan 24 '15 at 14:53
  • 1
    @MartinTörnwall - "C heap" is the generic term commonly used for heap inside the JVM which is not a part of the GC heap. As to how it's implemented, that depends on the OS it's running on (and there are many other environments beyond the one you imagine). – Hot Licks Jan 24 '15 at 15:01
  • 1
    @HotLicks ah the why do you care guy is here... Hello! – Koray Tugay Jan 24 '15 at 20:36

3 Answers3

16

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 - 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.)

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.

apangin
  • 92,924
  • 10
  • 193
  • 247
6

No, it's not overwritten, because there is usually no practical benefit in the two representations being at the same place. The JVM bytecode is just a piece of data. The JIT-emitted code is a stream of native CPU instructions (in some architectures, it is required that this is explicitly marked as executable).

Typically, when a new function is required for execution, the JIT compiler reads the bytecode of that function, allocates memory somewhere else, writes the equivalent native code to that memory, then returns a function pointer to the entry of the newly generated native code.

Theodoros Chatzigiannakis
  • 28,773
  • 8
  • 68
  • 104
  • 2
    Also: on many modern platforms you must explicitly ask for *executable* memory from the virtual memory subsystem. There's no good reason for bytecode to be allocated to an executable page. – Martin Törnwall Jan 24 '15 at 14:34
3

As far as I know, the The Java® Virtual Machine Specification does not specify any of that.
The only reference to JIT I can find is in Chapter 3:

[...] One example of such a translator is a just-in-time (JIT) code generator, which generates platform-specific instructions only after Java Virtual Machine code has been loaded. This chapter does not address issues associated with code generation, only those associated with compiling source code written in the Java programming language to Java Virtual Machine instructions.

So to my understanding, this can be done differently by different implementations.

However, to me it seems very unlikely that the memory containing the java bytecode is overwritten with native CPU instructions, because CPU instructions are technically executable and bytecode is just data, as it has to be interpreted. It wouldn't be impossible though, just very odd.

Siguza
  • 21,155
  • 6
  • 52
  • 89