The execution engine is one of the core components of a Java virtual machine. Both physical and virtual machines have the ability to execute code. The difference is that the execution engine of the physical machine is directly based on the processor, hardware, instruction set, and operating system level, and the execution engine of the virtual machine is implemented by itself, so you can specify the structure of the instruction set and the execution engine, and you can perform the instruction set format that is not directly supported by the hardware.
The virtual machine execution engine, when executing Java code, is divided into interpretation execution (through interpreter execution) and compilation execution (which produces native code execution through an instant compiler), and can be both.
The execution engine for all Java virtual machines is consistent: The byte code file is entered, the process is the equivalent of bytecode parsing, and the output is the execution result. Run-time stack frame structure
Stack frame, which is used to support the data structure of the virtual machine for method invocation and method execution, is the stack element of the virtual machine stack in the virtual Run-time data area. Information such as local variables, operand stacks, dynamic joins, and method return addresses are stored in the method. Each method from the call to execution completion, corresponds to a stack frame in the virtual machine stack from the stack to the process.
When compiling the code, the memory allocation of the stack frame has been determined and will not be affected by the program Run-time variable data, but only in the specific virtual machine implementation.
For the execution engine, in the active thread, only the stack frame at the top of the stack is valid, called the current stack frame, and the corresponding method is called the current method. All byte-code directives run by the execution engine operate only against the current stack frame. Local variable table
is a set of variable value storage space that is used to store the local variables defined within the method parameters and methods. When compiled into a class file, the max_locals of the method's code attribute determines its maximum capacity.
The capacity of a local variable table has a variable slot (Slot) as the smallest unit. Each slot can hold data of the basic data type, usually within 32 digits. The 64-bit virtual machine allocates two contiguous slot spaces (Double,long) with high alignment. For 64-bit, it is not allowed to access only one of them individually, or it throws an exception at the verification stage.
Method executes, the virtual machine uses the local variable table to complete the parameter value to the pass process of the parameter list. In order to save the stack frame space as much as possible, the slot in the local variable table can be reused. The scope of the variable defined in the method body does not necessarily overwrite the entire method body, and if the value of the current bytecode PC counter has exceeded the scope of a variable, then the corresponding slot of the variable can be given to other variables. Slot reuse can in some cases directly affect the system's garbage collection behavior.
The slot in the local variables table also has references to objects such as arrays, even if you leave the scope of the code, and after this, if you do not have any of the heap local variables table read and write operations, the reference used to occupy the slot has not been reused by other variables, So the local variable as part of the gcroots remains associated with it.
Public statci void Main (string[] args) {
byte[] a=new byte[64*1024*1024];//scope after GC
/////or below, and no memory recovery
{
byte[] a=new byte[64*1024*1024];//out of parentheses out of scope
}
//Add the following code, change the local variable table, memory is really recycled.
int a=0;
System.GC ();
}
Unused objects, which occupy a large amount of memory, can be manually assigned null, acting as int a=0 that sentence.
The class variable has two times the initial value of the process, once in the preparation phase, give the system the initial value, once in the initialization phase, give the program ape defined initial values. Therefore, it does not matter that the programmer does not assign a value to the class variable in the initialization phase, and it still has a definite initial value.
Local variables do not, not all are like int, Boolean has the default initial value, does not assign the initial value local variable is not available. Even if compiling a class file via or handwritten bytecode, the byte-code checksum is found by the virtual machine and the class load fails. Operand stacks
Also make Operation Stack, back into first out stack. The maximum depth is written in the max_stacks of the code attribute at compile time. Each element in the operand stack can be any Java data type, including long and double. 32-bit data types account for a capacity of 1, 64 bits account for 2. At any point in the execution of the method, the operand stack does not exceed the maximum depth set by Max_stacks.
The element data type in the operand stack must be strictly matched to the sequence of the byte code instruction, and if the I instruction is iadd, the top two of the stack are int and no long and float can appear.
On the conceptual model, the elements of two stack frames as virtual machines are independent of each other. However, in most virtual machine implementations, the two stack frames will overlap in some cases.
The Java Virtual machine interpretation execution engine, also known as the "stack based execution engine" stack, is the operand stack. Dynamic connection
Each stack frame contains a reference to the method that the stack frame belongs to in the Run-time pool, and holds the reference to support the dynamic connection during the invocation of the method.
Symbolic references, which are converted to direct references when the class is loaded or first used, that is, static parsing. While the other part is converted to a direct reference during the run, this part is a dynamic connection. Method return Address
When a method runs, there are only two ways to exit: one is that the execution engine encounters a byte-code instruction returned by any one method, and there may be a return value passed to the upper-level method caller, and whether the return value and the return value type will be determined according to the method returned by the command. This exit is called the normal completion of the exit.
In the second way, an exception was encountered during the execution of the method. And the exception is not processed in the method body, regardless of the exception generated within the Java Virtual machine or code using the Athrow byte code instruction, as long as no matching exception handler is found in the exception table of this method, it will cause the method to exit. This exit mode becomes abnormally complete exit. It does not return any value to the upper caller.
Method exit is equivalent to putting the current stack out of the stack, so the actions that can be performed when exiting are: Restoring the local variable table and operand of the upper method. Additional Information
That is, stack frame information. Dynamic connection, method return address, other information, etc. Method calls
Method invocations are not equivalent to method execution, the only task of the method invocation phase is to determine the version of the invoked method (that is, which method is invoked), and not to involve the specific running process inside the method for the time being. All method calls stored in the class file are only symbolic references, not the entry addresses (direct references) in the memory layout of the method at the actual runtime. Provides Java with powerful dynamic scalability, and makes it relatively complex, requiring that the target method's invocation be determined during class loading or running. Analytical
Symbolic references transform the parsing phase of a direct reference: The method has a predictable version of the call before the program actually runs, and the invocation version of the method is immutable during the run. This means that the calling target must be determined when the program code is written and the compiler compiles. The invocation of such a method is called parsing.
There are two main categories: static methods and Private methods. Because the former is directly associated with the type and the latter is inaccessible externally, it is not possible to override other versions by inheritance or otherwise, so it is appropriate to parse in the class load phase.
Java Virtual machine, 5 invocation byte code instruction,
Invokestatic, static method
Invokespecial (Invoke instance constructor method, private method, and parent method),
Invokevirtual, virtual methods (other than the above two and final methods)
Invokeinterface, an interface method, determines, at run time, an object that implements this interface.
Invokedynamic (the method referenced by the call-point qualifier is dynamically parsed at run time before the method is executed).
The final-modified method, although invoked by the Invokevirtual directive, is not a virtual method because it cannot be overwritten, there is no other version, no polymorphic selection is required, or its selection structure is unique.
When parsing a call, a static process is determined during the compilation, and the notation involved in the class is used to refer to all solder joints as a direct reference, without delay to the runtime to complete. Assigned
Dispatch calls can be static (compile-time completion) or dynamic (Run-time completion), and can be divided into single allocations and multiple allocations based on the number of variables (the caller of the method and the parameters of the method, collectively referred to as the method). The two types of dispatch mode 22 combination constitute static single dispatch, static multiple dispatch, dynamic single dispatch, dynamic multiple dispatch four kinds of distribution. Static Dispatch
To be continued, P247.