Definition of the Java virtual machine stack

Java Virtual Machine Stack (Java Virtual Machine Stack), also known as the Java Stack. When each thread is created, it creates a virtual Stack, which holds Stack frames that correspond to each Java method call. This Stack Frame is thread private.

The stack frame is used to store some information during the operation of the method, such as:

  • Local variable scale
  • The operand stack
  • Dynamic link
  • Method exit information

The vm stack has the following features:

  • Extremely fast, only second to PC registers.

  • The local variable table is created with the stack frame, its size is determined at compile time, and it only needs to be allocated a predetermined size when it is created. During the operation of the method, the size of the local variable scale does not change.

  • There are two types of exceptions to the Java virtual machine stack: StackOverFlowError and OutOfMemoryError.

    • StackOverFlowErrorIf the size of the Java virtual machine stack does not allow dynamic scaling, throw if the thread request stack depth exceeds the current maximum depth of the Java virtual machine stackStackOverFlowErrorThe exception.
    • OutOfMemoryErrorIf dynamic scaling is allowed, then when the thread requests the stack and runs out of memory, it can no longer scale dynamicallyOutOfMemoryErrorThe exception.
  • The Java virtual machine stack is also thread-private, created as a thread is created and destroyed as a thread terminates.

  • When StackOverFlowError occurs, there can be a lot more memory.

  • We can use the -xSS option to set the maximum stack space for threads

The process of pushing and unloading

When a local variable needs to be created during a method run, the value of the local variable is stored in the local variable table in the stack frame.

The stack frame at the top of the Java virtual machine stack is the currently executing active stack, that is, the currently executing method, and the PC register points to this address. Only the local variables of the active stack frame can be used by the operand stack. When another method is called in this stack frame, the corresponding stack frame is created again. The newly created stack frame is pushed to the top of the stack and becomes the current active stack frame.

After the method completes, the current stack frame is removed and the return value of the stack frame becomes an operand of the operand stack in the new active stack frame. If no value is returned, the operand of the operand stack in the new active stack frame does not change.

Since the Java virtual machine stack is thread-specific, data is not shared by threads (that is, thread private), so data consistency issues are not a concern, and synchronization locks are not an issue.

Local variable scale

An array of numbers used to store method parameters and local variables defined inside the method body. Data types include basic data types, object references, and return Address types.

The size of the local variable table is determined at compile time. The most basic storage unit is slot.

The number of nested calls to a method is determined by the stack size. In general, the larger the stack, the more nested method calls. For a function, the more parameters and local variables it has, which causes the local variable table to swell, the larger its stack frame will be to meet the need for more information to be passed through method calls. In turn, function calls take up more stack space, resulting in fewer nested calls.

Variables in the local variable table are only valid in the current method call. During method execution, the virtual machine passes the parameter values to the parameter variable list using the local variable table. When the method call ends, the local variable table is destroyed along with the method stack frame.

Slot:

  • The JVM assigns an access index to each slot in the local variable table, which successfully accesses the value of the local variable specified in the local variable table.
  • If the current frame is created by a constructor or instance method, the object that references this is stored in slot 0 with index, and the rest of the argument list continues in order.
  • The slots in the local variable table in the stack frame can be repeated. If a local variable goes out of its scope, the new local variable declared after its scope may reuse the slots of the expired local variable, so as to achieve the purpose of saving resources.
  • Types up to 32 bits occupy only one slot (including the returnAddress type), while 64-bit types (long and double) occupy two slots. Byte, short, and char are converted to int before storage. Boolean is also converted to int, where 0 means false and non-0 means true.

In the stack frame, the part most closely related to performance tuning is the local variable table. When the method is executed, the virtual machine uses the local variable table to complete the transfer method. The variables in the local variable table are also important garbage collection root nodes, as long as the objects referenced directly or indirectly in the local variable table are not recycled.

The operand stack

In addition to the local variable table, each independent Stack frame also contains a last-in-first-out operand Stack, which can also be called the Expression Stack. During method execution, data is written to or extracted from the Stack according to bytecode instructions. That is, push and pop.

Operand stack, mainly used to store the intermediate results of the calculation process, and as a temporary storage space for variables during the calculation process.

The operand stack is a workspace for the JVM execution engine. For example, if the local variable table is a shelf, the operand stack is like a workbench. When an item needs to be repaired or assembled, it is brought to the workbench (push), and when the operation is finished, it is taken away (pop).

  • Each operand stack has an explicit stack depth for storing values, the maximum depth being defined at compile time. The 32bit type occupies one stack unit depth and the 64bit type occupies two stack unit depth operand stacks.
  • Instead of accessing the index, data can only be accessed once through the standard push and push operations.

As mentioned earlier, stack-based virtual machines use more compact zero-address instructions, but completing an operation requires more loading and unloading instructions, which means more instruction dispatches and memory reads/writes. Because operands are stored in memory, frequent memory read/write operations inevitably affect execution speed. In order to solve this problem, the designers of HotSpot JVM proposed Tos (top-of-stack Cashing) technology, which caches all the top-of-stack elements in the registers of the physical CPU to reduce the number of reads/writes to memory and improve the execution efficiency of the execution engine.

Dynamic joins (or method references to run-time constant pools)

Each stack frame contains an internal reference to the method that the stack frame belongs to in the runtime constant pool. The purpose of including this reference is for the code supporting the current method to achieve Dynamic Linking.

When a Java source file is compiled into a bytecode file, all variable and method references are kept as Symbolic references in the class file’s constant pool. For example, describing a method that calls another method is represented by symbolic references to the method in the constant pool. The purpose of dynamic linking, then, is to convert these symbolic references into direct references to the calling method.

Method call

In the JVM, converting a symbolic reference to a direct reference to a calling method is related to the method binding mechanism, which extends the method invocation here:

  • Static linking: When a bytecode file is loaded into the JVM, the process of reducing the caller’s symbolic reference to a direct reference is called static linking if the target method being called is known at compile time and remains unchanged at run time.
  • Dynamic linking: If the invoked method cannot be determined at recompile time, the symbolic reference of the invoked method can only be converted into a direct reference at run time. This reference conversion process is dynamic, so it is called dynamic linking.
  • Methods the binding
    • Early binding: The target method being called is known at recompile time and the run time remains the same.
    • Late binding: the method being called cannot be determined at compile time, and only the related method can be bound to the actual type at run time.
  • Non-virtual methods: If the specific version of a method is called at compile time, it is immutable at run time. Such methods are called non-virtual methods static methods, private methods, final methods, instance constructors, superclass methods are all non-virtual methods, and everything else is virtual.
  • Virtual method table, object-oriented programming, it will be very frequent use dynamic allocation, if every time the process of dynamic allocation to metadata method in the class to search the right goal, may affect the execution efficiency, so in order to improve the performance, the JVM area using the method of the class to build a virtual method table, using the index table instead of a search.
    • Each class has a virtual method table that holds the actual entry to each method.
    • The virtual method table is created and initialized during the linking phase of the class load, and the JVM initializes the class’s methods after the class’s variable initializers are ready.
  • The nature of method rewriting
    • Find the actual type of the object executed by the first element at the top of the operand stack and call it C. If a method is found in type C that matches both the descriptor and the simple name in the constant pool, access verification is performed.
    • If it passes, a direct reference to the method is returned, and the search process ends. If not through, it returns the Java. Lang. IllegalAccessError anomalies.
    • Otherwise, search and verify each parent class of C from bottom to top according to inheritance relationship.
    • If didn’t find the right way, it throws the Java. Lang. AbstractMethodError anomalies.

Whereas any ordinary method in Java has the characteristics of a virtual function (runtime validation, late binding), C++ is explicitly defined using the keyword virtual. If you do not want a method to have the characteristics of a virtual function ina Java program, you can mark the method with the keyword final.

Private methods, final methods, instance constructors, and superclass methods are all non-virtual methods, and everything else is virtual. If a method can be rewritten, the version of the call cannot be determined at compile time. Methods that cannot be overridden and whose version of the call can be determined at compile time are non-virtual.

Method return address

Holds the value of the PC register that called the method. There are two ways to end a method:

  • Normal Execution Completed

  • Unhandled exception, abnormal exit

Either way, the method is returned to where it was called after it exits. When a method exits normally, the value of the caller’s PC counter is returned as the address of the next instruction that calls the method. However, if an exception exits, the return address is determined by the exception table, which is generally not stored in the stack frame.

In essence, the method exit is the process of the current stack frame out of the stack. At this point, you need to restore the local variable table of the upper method, operand stack, push the return value into the operand stack of the caller’s stack frame, set the PC register value, etc., and let the caller’s method continue to execute.

conclusion

The Java virtual machine stack is also thread-private, created as a thread is created and destroyed as a thread terminates. It holds Stack frames, corresponding to each Java method call, that are thread private.

Basic components of the Java virtual machine stack:

  • Local variables table: Used to store method parameters, local variables defined within the method body
  • Operand stack: Mainly used to store the intermediate results of the calculation process and as a temporary storage space for variables during the calculation (equivalent to the console)
  • Dynamic connection: A method reference to the runtime constant pool
  • Method return address: holds the value of the PC register that called the method

There are two types of exceptions to the Java virtual machine stack: StackOverFlowError and OutOfMemoryError.

  • StackOverFlowErrorIf the size of the Java virtual machine stack does not allow dynamic scaling, throw if the thread request stack depth exceeds the current maximum depth of the Java virtual machine stackStackOverFlowErrorThe exception.
  • OutOfMemoryErrorIf dynamic scaling is allowed, then when the thread requests the stack and runs out of memory, it can no longer scale dynamicallyOutOfMemoryErrorThe exception.

Often meet try:

  1. Example stack overflow?

StackOverflowError occurs when the program recurses or the recursion is nested to a certain extent. You can use -xss to set the stack memory to be larger and delay the error timing, but it cannot be avoided.

  1. Can stack size be adjusted to prevent overflow?

No guarantee against overflow

  1. Is it better to allocate more stack memory?

No, it reduces the OOM probability for a while, but it takes up space for other threads because the space is limited.

  1. Does garbage collection involve the virtual machine stack?

Don’t.

  1. Are local variables defined in a method thread-safe?

Case by case. An object is thread-safe if it is created internally and dies internally without being returned externally, and thread-unsafe if it is not.