Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is a virtual machine stack?

2025-01-31 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article mainly introduces "what is a virtual machine stack". In daily operation, I believe that many people have doubts about what a virtual machine stack is. The editor consulted all kinds of materials and sorted out simple and easy-to-use operation methods. I hope it will be helpful for you to answer the doubts about "what is a virtual machine stack"! Next, please follow the editor to study!

Virtual machine stack-Overview of virtual machine stack

Because of the cross-platform design, the instructions of Java are designed according to the stack. Different platforms have different CPU architectures, so they cannot be designed to be register-based.

The advantage is cross-platform, the instruction set is small, the compiler is easy to implement, the disadvantage is the performance degradation, to achieve the same function requires more instructions.

Many Java developers refer to the Java memory structure with a very coarse-grained understanding of the memory area in JVM as just Java heap (heap) and Java stack (stack). Why?

First of all, the stack is the unit of runtime, and the heap is the unit of storage.

The stack solves the problem of running the program, that is, how the program executes, or how to deal with data.

Heap solves the problem of data storage, that is, how and where to put the data.

What is the Java virtual machine stack?

Java virtual machine stack (Java Virtual Machine Stack), also known as Java stack in the early days. When each thread is created, it creates a virtual machine stack, in which a stack frame (Stack Frame) is stored, corresponding to a series of Java method calls.

Is private to the thread

Life cycle

The life cycle is consistent with the thread, that is, the thread ends, and the virtual machine stack is destroyed.

Action

In charge of the operation of the Java program, it saves the local variables of the method (8 basic data types, the reference address of the object), part of the results, and participates in the call and return of the method.

A local variable, which is compared to a member variable (or attribute)

Basic data type variables VS reference type variables (classes, arrays, interfaces)

Characteristics of stack

Stack is a fast and effective way to allocate storage, and its access speed is second only to program counters.

JVM has only two operations directly on the Java stack:

Each method executes, accompanied by the stack (stack, stack)

Execute the stack work at the end of the execution.

There is no garbage collection problem for the stack (there is an overflow of the stack)

What exceptions are encountered in development?

Possible exceptions in the stack

The Java virtual machine specification allows the size of the Java stack to be dynamic or fixed.

If a fixed-size Java virtual machine stack is used, the Java virtual machine stack capacity of each thread can be selected independently when the thread is created. If the thread requests that the stack capacity exceed the maximum allowed for the Java virtual machine stack, the Java virtual machine will throw a StackOverflowError exception.

If the Java virtual machine stack can be expanded dynamically and cannot apply for enough memory when trying to extend, or if there is not enough memory to create the corresponding virtual machine stack when creating a new thread, the Java virtual machine will throw an OutOfMemoryError exception (out of memory).

Exception in the demo stack: StackOverflowError

Public class StackErrorTest {private static int count = 1; public static void main (String [] args) {System.out.println (count++); main (args);}}

When the stack depth reaches 9803, the stack memory space is insufficient.

Set stack memory size

We can use the parameter-Xss option to set the maximum stack space of the thread. The size of the stack directly determines the maximum reachable depth of the function call.

-what is stored in the storage unit 1 stack of the Xss1m-Xss1024k 2 stack?

Each thread has its own stack, and the data in the stack is in the format of Stack Frame.

Each method being executed on this thread corresponds to a Stack Frame.

The stack frame is a memory block and a data set, which maintains all kinds of data information during the execution of the method.

Review:

Basic concepts of OOP: classes and objects

Basic structure in the class: field (attributes, fields, fields), method

2 stack operation principle

JVM has only two operations directly on the Java stack, that is, pressing and unloading the stack frame, following the principle of "first in, last out" / "last in, first out".

In an active thread, there is only one active stack frame at a point in time. That is, only the stack frame (top stack frame) of the method currently being executed is valid, this stack frame is called the current stack frame (Current Frame), the method corresponding to the current stack frame is the current method (Current Method), and the class that defines this method is the current class (Current Class).

All bytecode instructions run by the execution engine operate only for the current stack frame.

If other methods are called in this method, the corresponding new stack frame is created and placed at the top of the stack to become the new current frame.

Let's write a simple code

/ * Stack frame * * / public class StackFrameTest {public static void main (String [] args) {method01 ();} private static int method01 () {System.out.println ("start of method 1"); int I = method02 (); System.out.println ("end of method 1"); return I } private static int method02 () {System.out.println ("start of method 2"); int I = method03 (); System.out.println ("end of method 2"); return I;} private static int method03 () {System.out.println ("start of method 3"); int I = 30 System.out.println ("end of method 3"); return I;}}

The output is

The beginning of method 1, the beginning of method 2, the beginning of method 3, the end of method 3, the end of method 2, the end of method 1.

It satisfies the concept of stack first in and then out. Through the DEBUG of Idea, you can see the stack information.

Stack operation principle

Stack frames contained in different threads are not allowed to reference each other, that is, it is impossible to reference another thread's stack frame in one stack frame.

If the current method calls another method, when the method returns, the current stack frame will send the execution result of this method back to the previous stack frame, and then the virtual machine discards the current stack frame, making the previous stack frame become the current stack frame again.

The Java method has two ways to return a function, one is a normal function return, using the return instruction, and the other is to throw an exception. No matter which method is used, it will cause the stack frame to be popped.

3 the internal structure of stack frames

Stored in each stack frame is:

Local variable scale (Local Variables)

Operand stack (operand Stack) (or expression stack)

Dynamic linking (DynamicLinking) (or a method reference to the runtime constant pool)

Method return address (Return Address) (or definition of normal or abnormal exit of a method)

Some additional information

Parallel the stack under each thread is private, so each thread has its own stack, and there are many stack frames in each stack, the size of which is mainly determined by the local variable table and Operand stack.

Three-local variable scale

Local variable scale: Local Variables, which is called local variable array or local variable scale.

Defined as an array of numbers, it is mainly used to store method parameters and local variables defined in the method body. These data types include various basic data types, object references (reference), and returnAddress types.

Because the local variable table is built on the stack of the thread and is the private data of the thread, there is no data security problem.

The capacity required for the local variable table is determined at compile time and saved in the maximum local variables data item of the Code property of the method. The size of the local variable table will not be changed during the operation of the method.

The number of calls to a method is determined by the size of the stack. In general, the larger the stack, the more method nesting calls. For a function, the more its parameters and local variables, the larger the stack frame of the local variable table, in order to meet the need for more information to be transmitted by the method call. In turn, function calls will take up more stack space, resulting in a reduction in the number of nested calls.

The variables in the local variable table are valid only in the current method call. When the method is executed, the virtual machine completes the process of transferring the parameter values to the list of parameter variables by using the local variable table. When the method call ends, with the destruction of the method stack frame, the local variable table will also be destroyed.

1 understanding of Slot

The storage of parameter values always starts at index 0 of the array of local variables and ends at the index of the array length-1.

Local variable scale, the most basic storage unit is Slot (variable slot)

The local variable table stores various basic data types (8 kinds), reference type (reference) and returnAddress type variables that can be known at the compilation time.

In the local variable table, types less than 32 bits occupy only one slot (including returnAddress types), and 64-bit types (1ong and double) occupy two slot.

Byte, short, char, float are converted to int,boolean before storage and are also converted to int,0 for false, and non-zero for true. 1ong and double occupy two slot.

JVM assigns an access index to each Slot in the local variable table, through which the local variable value specified in the local variable table can be successfully accessed.

When an instance method is called, its method parameters and local variables defined within the method body will be copied sequentially to each slot in the local variable table.

If you need to access the local variable value of a 64bit in the local variable table, you only need to use the previous index. (for example, accessing variables of type long or double)

If the current frame is created by a constructor or instance method, the object reference this will be stored at the slot with an index of 0, and the rest of the parameters will continue to be arranged in the order of the parameter table.

Reuse of Slot

The slot in the local variable table in the stack frame can be reused. If a local variable goes beyond its scope, then the new local change declared after its scope is likely to reuse the slot of the expired local variable. In order to achieve the purpose of saving resources.

2 examples: comparison between static variables and local variables

Classification of variables:

By data type: basic data type, reference data type

By the position declared in the class:

Class variable: the prepare phase of linking, which assigns the class variable by default, and the initial phase displays the assignment to the class variable, that is, the static code block assignment

Instance variable: as the object is created, the instance variable space is allocated in the heap space and assigned by default

Member variable {class variable (static modifier), instance variable}, local variable

Local variables: must be explicitly assigned before use! Otherwise, the compilation will fail

After the parameter table is assigned, it is allocated according to the order and scope of the variables defined in the method body.

We know that the class variable table has two opportunities to initialize, the first is in the "preparation phase", the system initialization is performed, the class variable is set to zero, and the other is in the "initialization" phase, which gives the programmer the initial value defined in the code.

Unlike class variable initialization, there is no system initialization process in the local variable table, which means that once a local variable is defined, it must be initialized artificially, otherwise it cannot be used.

Supplementary note:

In the stack frame, the part most closely related to performance tuning is the local variable table mentioned above. When the method is executed, the virtual machine uses the local variable table to complete the transmission of the 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 will not be recycled.

Four Operand stack concept

Stack: can be implemented using arrays or linked lists

Operand stack: Operand Stack

Each independent stack frame contains not only a local variable table, but also a Last-In-First-Out Operand stack, which can also be called expression stack (Expression Stack).

Operand stack. During method execution, data is written to or extracted from the stack according to bytecode instructions, that is, push and pop.

Some bytecode instructions push values into the Operand stack, while other bytecode instructions fetch operands out of the stack. Use them and then press the results into the stack

For example, perform operations such as copy, exchange, summation, etc.

Code example

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

The Operand stack is a workspace of the JVM execution engine. When a method begins to execute, a new stack frame is created, and the Operand stack of this method is empty. .

At this time, the array is long, because once the array is created, it is immutable.

Each Operand stack has a clear stack depth for storing values, and the maximum depth required is defined at compile time and stored in the method's Code property, which is the value of maxstack.

Any element in the stack is an arbitrary Java data type

The type of 32bit occupies a stack unit depth

The type of 64bit occupies two stack unit depths

The Operand stack does not access the data by accessing the index, but can only access the data once through standard stack-in and out-stack operations.

If the called method has a return value, the return value will be pressed into the Operand stack of the current stack frame and the next bytecode instruction to be executed in the PC register will be updated.

The data type of the elements in the Operand stack must strictly match the sequence of bytecode instructions, which is verified by the compiler during the compiler and again in the data flow analysis phase of the class verification phase in the class loading process. | |

In addition, we say that the interpretation engine of the Java virtual machine is a stack-based execution engine, where the stack refers to the Operand stack.

Five code tracking

We give the code

Public void testAddOperation () {byte I = 15; int j = 8; int k = I + j;}

Use the javap command to decompile the class file: javap-v class name.class

Byte, short, char and boolean are all saved using int type.

We can see from the above code that we all stack operands 15 and 8 through bipush.

At the same time, the iadd method is used for the addition operation. I-> represents the int, that is, the addition operation of the int type.

The execution process is as follows:

First execute the first statement, the PC register points to 0, that is, the instruction address is 0, and then use bipush to put the Operand 15 on the stack.

After execution, let PC + 1 point to the next line of code, and the next line of code is to store the elements of the Operand stack to the location of the local variable table 1. We can see that an element has been added to the local variable table.

Why doesn't the local variable scale start with 0?

In fact, the local variable table also starts from 0, but because the position 0 stores the this pointer, it is omitted directly.

Then PC+1 points to the next line. Let Operand 8 also enter the stack, perform store operation at the same time, and store it in the local variable table.

Then, from the local variable table, put the data in the Operand stack in turn.

Then the two elements in the Operand stack are added and stored in the local variable table 3.

Finally, if the location of the PC register points to 10, that is, the return method, you will directly exit the method.

The difference between iTunes + and + + I

Six-stack top cache technology

Top Stack caching Technology: Top Of Stack Cashing

As mentioned earlier, virtual machines based on stack architecture use more compact zero-address instructions, but more on-and off-stack instructions are required to complete an operation, which means more instruction instruction dispatch and memory read / write times will be required.

Because operands are stored in memory, frequent memory read / write operations will inevitably affect the execution speed. In order to solve this problem, the designers of HotSpot JVM proposed the top-of-stack cache (Tos,Top-of-Stack Cashing) technology, which caches all the top elements in the register of the physical CPU, so as to reduce the number of reads / writes to memory and improve the execution efficiency of the execution engine.

Registers: fewer instructions and faster execution

Seven dynamic links (or method references to run-time pools)

Dynamic links: Dynamic Linking

Dynamic links, method return addresses, additional information: some places are called frame data areas

Each stack frame contains a reference to the method to which the stack frame belongs in the runtime constant pool. The purpose of this reference is to enable code that supports the current method to implement dynamic linking (Dynamic Linking). For example: invokedynamic instruction

When the Java source file is compiled into a bytecode file, all variable and method references are saved as symbolic references (symbolic Reference) in the constant pool of the class file. For example, when a method calls another method, it is represented by symbolic references to the method in the constant pool, then the purpose of dynamic linking is to convert these symbolic references into direct references to the calling method.

Why do I need to run the constant pool?

Because constants or methods may be called in different methods, only one copy needs to be stored, saving space

The function of constant pool is to provide some symbols and constants to facilitate the identification of instructions.

Eight method calls: parsing and allocation

In JVM, converting a symbolic reference to a direct reference to a calling method is related to the binding mechanism of the method

Link static link

When a bytecode file is loaded inside JVM, if the target method being called is known at compile time and the run time remains unchanged, the process of converting the symbolic reference of the calling method into a direct reference is called a static link.

Dynamic link

If the called method cannot be determined at compile time, that is, the symbol of the called method can only be converted into a direct reference at run time of the program, because this reference conversion process is dynamic, it is also called dynamic linking.

Binding mechanism

The binding mechanisms of the corresponding methods are early binding (Early Binding) and late binding (Late Binding). Binding is a process in which a field, method, or class is replaced by a direct reference when a symbolic reference is replaced, which occurs only once.

Early binding

Early binding means that if the called target method is known at compile time and the run time remains the same, it can be bound to the type it belongs to, so that since it is clear which target method is called, it is possible to use static links to convert symbolic references into direct references.

Late binding

If the called method cannot be determined at compile time, it can only bind the relevant method according to the actual type at run time, which is also called late binding.

The development history of early and late binding

With the emergence of high-level languages, there are more and more object-oriented programming languages like Java. Although these programming languages have some differences in syntax style, they always have one thing in common with each other, that is, they all support object-oriented features such as encapsulation, inheritance and polymorphism. Then naturally there are two binding methods: early binding and late binding.

Any ordinary method in Java actually has the characteristics of virtual functions, which are equivalent to virtual functions in the C++ language (C++ needs to be explicitly defined using the keyword virtual). If you don't want a method to have the characteristics of a virtual function in a Java program, you can mark the method with the keyword final.

Virtual method and non-virtual method

If the method determines the specific version of the call at compile time, this version is immutable at run time. Such a method is called a nonvirtual method.

Static methods, private methods, final methods, instance constructors, and parent methods are all non-virtual methods.

Other methods are called virtual methods.

The premise for the use of the polymorphism of subclass objects

Inheritance relationship of class

Method rewriting

The following method invocation instructions are provided in the virtual machine: normal invocation instructions:

1 invokestatic: the static method is called, and the unique method version is determined in the parsing phase

2 invokespecial: call methods, private and parent methods, and determine the unique method version in the parsing phase

3 invokevirtual: call all virtual methods

4 invokeinterface: call the API method

Dynamically invoke instructions:

5 invokedynamic: dynamically parse the method that needs to be called, and then execute

The first four instructions are fixed in the virtual machine, the method call execution can not be interfered by human, while the invokedynamic instruction supports the method version determined by the user. The methods called by the invokestatic instruction and the invokespecial instruction are called non-virtual methods, and the rest (except those decorated by final) are called virtual methods.

About the invokednamic instruction

The JVM bytecode instruction set has been relatively stable until an invokedynamic instruction was added to Java7, which is an improvement made by Java to [implement dynamically typed language support].

However, there is no method to generate invokedynamic instructions directly in Java7, so we need to use ASM, an underlying bytecode tool, to generate invokedynamic instructions. It was not until the emergence of the Lambda expression of Java8 and the generation of invokedynamic instructions that there was a direct way to generate the invokedynamic instruction in Java.

The essence of the dynamic language type support added in Java7 is the modification of the Java virtual machine specification, rather than the modification of the Java language rules, which is relatively complex and increases the method calls in the virtual machine. The most direct beneficiary is the dynamic language compiler running on the Java platform.

Dynamically typed language and statically typed language

The difference between dynamically typed language and statically typed language lies in whether the type is checked at compile time or run time. The former is statically typed language, on the contrary, it is dynamically typed language.

To put it bluntly, the statically typed language is the type information that judges the variable itself; the dynamic typed language is the type information that judges the value of the variable, which is an important feature of the dynamic language.

Java:String info = "mogu blog"; (Java is a statically typed language and will be compiled first for type checking)

JS:var name = "shkstart"; var name = 10; (check only at runtime)

The essence of method rewriting the nature of method rewriting in the Java language

Find the actual type of object executed by the first element at the top of the Operand stack and write it down as C.

If a method is found in type C that matches the simple name described in the constant, an access check is performed, if passed, a direct reference to this method is returned, and the lookup process ends; if not, a java.lang.IllegalAccessError exception is returned.

Otherwise, each parent class of C is searched and verified in step 2 according to the inheritance relationship.

If the appropriate method is never found, a java.lang.AbstractMethodError exception is thrown.

IllegalAccessError introduction

The program attempts to access or modify a property or call a method that you do not have permission to access. In general, this causes a compiler exception. If this error occurs at run time, it indicates that an incompatible change has taken place in a class.

Method invocation: virtual method table

Dynamic dispatch is frequently used in object-oriented programming, and execution efficiency may be affected if it is necessary to re-search the class's method metadata for appropriate targets during each dynamic dispatch. Therefore, in order to improve performance, JVM is implemented by establishing a virtual method table (virtual method table) in the method area of the class (non-virtual methods do not appear in the table). Use index tables instead of lookups.

There is a virtual method table in each class that holds the actual entry of each method.

When was the virtual method table created?

The virtual method table is created and initialized during the linking phase of the class load, and JVM initializes the method table of the class after preparing the initial values of the class's variables.

As shown in the figure above: if the method is overridden in the class, it will be looked up directly in the virtual method table when called, otherwise it will be directly connected to the method in Object.

Nine methods return address

Stores the value of the pc register that calls the method.

There are two ways to end a method:

Normal execution completed

An unhandled exception occurred and exited abnormally

No matter which way you exit, you return to the location where the method was called after the method exits. When the method exits normally, the value of the caller's pc counter is used as the return address, that is, the address of the next instruction of the instruction that called the method. If you exit with an exception, the return address is determined by the exception table, and this information is not generally saved in the stack frame.

When a method starts to execute, there are only two ways to exit the method:

When the execution engine encounters a bytecode instruction (return) returned by any method, the return value is passed to the upper method caller, which is referred to as the normal completion exit.

Which return instruction a method needs to use after a normal call is completed depends on the actual data type of the method's return value.

In bytecode instructions, the return instruction contains ireturn (used when the return value is of type boolean,byte,char,short and int), lreturn (type Long), freturn (type Float), dreturn (type Double), and areturn. There is also a return instruction declared as a void method, which is used by instance initialization methods and initialization methods for classes and interfaces.

An exception (Exception) is encountered during the execution of the method, and the exception is not handled in the method, that is, as long as no matching exception handler is found in the exception table of the method, it will cause the method to exit, namely the exception completion exit.

During the execution of the method, the exception handling when an exception is thrown is stored in an exception handling table, which is convenient to find the code that handles the exception when an exception occurs.

In essence, the exit of the method is the process of unstacking the current stack frame. At this point, it is necessary to restore the local variable table of the upper method, the Operand stack, press the return value into the Operand stack of the caller stack frame, set the PC register value, and so on, so that the caller method can continue to execute.

The difference between normal completion exit and abnormal completion exit is that exiting through abnormal completion does not generate any return value to its upper-level caller.

Ten additional information

Additional information related to the implementation of the Java virtual machine is also allowed in the stack frame. For example: information that supports program debugging.

The relevant interview questions of National Day holiday stack

For example, the case of stack overflow? (StackOverflowError)

Set the size of the stack with-Xss

Adjust the stack size to ensure that there is no overflow?

There is no guarantee that it will not overflow

The larger the allocated stack memory, the better?

No, it reduces the probability of OOM for a certain period of time, but it will crowd out other thread space because the whole space is limited.

Does garbage collection involve virtual machine stacks?

No.

Are the local variables defined in the method thread-safe?

Concrete analysis of specific problems

Is it thread safe to define local variables in the / * * interview question * method? Specific situation specific analysis * what is thread safety? * if only one thread can manipulate this data, it must be thread-safe * if there are multiple threads, the data is shared, and if the sharing mechanism is not considered, it is not thread-safe * / public class StringBuilderTest {/ S1 is declared by thread-safe public static void method01 () {/ / thread. Belongs to the local variable StringBuilder S1 = new StringBuilder () S1.append ("a"); s1.append ("b");} / / this is also thread unsafe, because there is a return value that may be called by other programs public static StringBuilder method04 () {StringBuilder stringBuilder = new StringBuilder (); stringBuilder.append ("a"); stringBuilder.append ("b"); return stringBuilder } / / stringBuilder is thread unsafe, operating on shared data public static void method02 (StringBuilder stringBuilder) {stringBuilder.append ("a"); stringBuilder.append ("b");} / * concurrent execution will lead to thread unsafe problems * / public static void method03 () {StringBuilder stringBuilder = new StringBuilder () New Thread (()-> {stringBuilder.append ("a"); stringBuilder.append ("b");}, "T1"). Start (); method02 (stringBuilder);} / / StringBuilder is thread-safe, but String may also be thread-safe public static String method05 () {StringBuilder stringBuilder = new StringBuilder (); stringBuilder.append ("a") StringBuilder.append ("b"); return stringBuilder.toString ();}}

To sum up: if an object is generated internally, dies internally, and does not return to the outside, then it is thread-safe, and vice versa.

Is there an Error and GC in the runtime datazone?

Whether there is an Error in the runtime data area, whether there is a GC program counter, whether there is a virtual machine stack, whether the local method stack is (OOM) is a heap is this, the study on "what is a virtual machine stack" is over, hoping to solve everyone's doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report