Home >Java >javaTutorial >Detailed graphic explanation of JMM java memory model

Detailed graphic explanation of JMM java memory model

高洛峰
高洛峰Original
2017-03-19 11:47:571573browse

JMM is an inevitable level for a programmer who wants to understand Java in depth. This article is more theoretical and is as easy to understand as possible. I hope you can correct me if there are any mistakes.

Let’s talk about the main memory allocation of jvm first

 JMM java内存模型图文详解

 1 java virtual machine stack (java virtual stack)

The virtual machine stack is private to the thread. Each thread has its own virtual machine stack, which is the memory for java method execution. Model, when each method is executed Create a stack frame on the virtual machine stack. The stack frame is a data structure that mainly stores the local variables (basic type, reference to the object , return Address type (pointing to the address of a bytecode instruction)), operation stack (referring to the stack of operation instructions after method compilation), dynamic linking, method exit. Generally speaking, Java memory is divided into stack and heap, and the stack refers to the virtual machine stack. But Java's memory allocation is not that simple.

The dynamic link is explained as follows:

Each stack frame contains a reference to the method to which the stack frame belongs in the execution runtime constant . This reference is held for Supports dynamic linking (Dynamic Linking) during method calling.

Class A large number of symbol references are stored in the file. The method call instructions in the bytecode take the symbol references pointing to the methods in the constant pool as parameters. Some of these symbol references will be converted into direct references during the class loading phase or when used for the first time. This conversion is called staticparsing. The other part will be converted into a direct reference during each run, this part is called dynamic connection.

The explanation of method exit is as follows:

  • When execution encounters a return instruction, the return value will be passed to the upper method caller. This exit method is called Normal completion exit (Normal Method Invocation Completion). Generally speaking, the caller's PC counter can be used as the return address.

  • When an exception is encountered during execution and the current method body is not processed, it will cause the method to exit. At this time, there is no return value, which is called Abrupt Method Invocation Completion. ), the return address must be determined through the Exception handler table.

There will be two exceptions in the virtual machine stack, one is the common OOM and the other is StackOverFlowError. StackOverflowError is generally caused by recursive calls. The stack depth is also limited in the virtual machine, otherwise the virtual machine will cry if it is unrestricted recursive call. Needless to say, OOM will occur when the requested memory is greater than what is currently held by the virtual machine stack (the virtual machine stack space can be dynamically expanded, but the memory allocated to the jvm is also limited, so the virtual machine stack is not infinitely expandable) of).

 2 Local method stack

The local method stack and the virtual machine stack are basically similar, except that the virtual machine stack executes class bytecode, while the local method stack What is executed in the method stack is the service of the local method, which is actually calling some different implementations of the same method written in C or C++ according to different OS platforms.

 3 Method area

The method area is an area shared by threads and is used to store class information that has been loaded by the virtual machine ( class For bytecode data, it should be noted here that if you load a lot of classes at the same time, you need to increase the space in the method area, otherwise it will cause OOM. This can only be done when there are few classes. If there are too many classes, you can use lazy loading. Such as spring's lazy loading mechanism, try to avoid loading too many classes), constants, static variables and code compiled by the just-in-time compiler (JIT) and other data at the same time. The method area is actually what we call the permanent generation area ( is limited to the implementation mechanism of the hotspot virtual machine). The reason why it is called the permanent generation is that the data here is rarely garbage collected because of the loading Classes will not die out in a short while. Many methods will create objects in the heap based on the class. Static variables are generally the root nodes of gc and search algorithms, while constants will not change at all. The data is rarely cleaned.

The Java virtual machine specification also has very loose restrictions on this area. In addition to being a physically discontinuous space, it also allows fixed size and scalability, and does not need to implement garbage collection. Relatively speaking, garbage collection behavior is relatively rare in this area (so more attention should be paid to the definition of constants and static variables). Memory collection in the method area will still occur, but the memory collection in this area is mainly for the recycling of the constant pool and the unloading of types.

Generally speaking, memory recycling in the method area is difficult to satisfy. When the method area cannot meet the memory allocation requirements, an OutOfMemoryError exception will be thrown.

 4 Runtime constant pool

 Before JDK1.6StringThe constant pool is located in the method area.
The JDK1.7 string constant pool has been moved to the heap.

Java is a dynamically connected language. The role of the constant pool is very important. In addition to the various basic types defined in the code (such as int, long, etc.) and object types (such as String and array), also include some symbol references in text form, such as:

The fully qualified names of classes and interfaces;

The names and descriptors of fields;

The names and descriptors of methods.

In C language, if a program wants to call a function in another library, when connecting, the position of the function in the library (that is, relative to the library The offset at the beginning of the file) will be written in the program. At runtime, the function is called directly at this address;

In the Java language, everything is dynamic. When compiling, if a call to other class methods or a reference to other class fields is found, what is recorded in the class file can only be a symbol reference in text form. During the connection process, the virtual machine searches based on this text information. The corresponding method or field.

Therefore, unlike the so-called "constants" in the Java language, the content of the "constants" in the class file is very rich. These constants are concentrated in an area in the class, one after the other, here they are called is the "constant pool".

The constant pool technology in Java appears to create certain objects conveniently and quickly. When an object is needed, you can take one out of the pool (if there is not one in the pool, create one). This saves a lot of time when you need to repeatedly create equal variables. The constant pool is actually a memory space, which is different from the heap space where objects created using the new keyword are located.

The entire constant pool will be referenced by an index of the JVM. Just like the collection of elements in the array is accessed according to the index, the JVM also processes the information stored in these constant pools according to the index method. In fact, the constant pool is in the Java program The dynamic link process plays a vital role (mentioned above). The following is excerpted from "In-depth Understanding of Java Virtual Machine".

In addition to the class version, fields, methods, interfaces and other information, there is also information in the Class file that the constant pool is used to store various literals and symbol references generated by the compiler. This part of the information will After the class is loaded, it is stored in the runtime constant pool in the method area. The Java virtual machine has strict regulations on every part of the class (including the constant pool). What kind of data is used to store each byte must have specification requirements, so that it can be recognized, loaded and executed by the virtual machine. Generally speaking, in addition to saving the symbol references described in the Class file, the translated direct references are also stored in the runtime constant pool.

Another important feature of the runtime constant pool compared to the Class file constant pool is that it is dynamic. The Java virtual machine does not require that constants can only be generated during compilation, that is, they are not preset into the Class file constant pool. Only the content can enter the runtime constant pool in the method area. New constants can also be put into the constant pool during running.

The constant pool is part of the method area, so it is limited by memory. When it cannot apply for enough memory, an OutOfMemoryError exception will be thrown

 5 Heap

The heap is the largest area in memory, the only place used to store object instances. This place is also the main battlefield of the gc algorithm. However, with the development of JIT (just in time compilation) and the maturity of escape technology, not all objects are created on the heap. The following is an excerpt from "In-depth Understanding of the Java Virtual Machine".

In the Java programming language and environment, the JIT compiler (just-in-time compiler) is a program that converts Java bytecode (including instructions that need to be interpreted) A program that converts instructions into instructions that can be sent directly to the processor. When you write a Java program, the source language statements will be compiled into bytecode by the Java compiler, rather than compiled into instruction code corresponding to a specific processor hardware platform (for example, Intel's Pentium microprocessor or IBM's System/390 processor). Bytecode is platform-independent code that can be sent to any platform and run on that platform.

The memory allocation of java is roughly like this. The jvm is also equipped with many parameters to adjust the above data. I will not list them here, but will explain them in detail in a separate gc-related article. Let's talk about how JVM handles the problems caused by concurrency in the era of multi-core processors.

 Concurrency control

 Multi-core CPU can execute multiple threads concurrently, and each thread has its own local workspace ( In fact, it is the system cache and register assigned to each core), which stores the data obtained from the main memory above and makes a copy to run in the work area. If the data is shared among multiple threads, and the threads are Data exchange cannot be performed, which involves the problem of inconsistent data in shared variables. Java controls the visibility of shared variables through mechanisms such as sychronized volatile Lock.

JMM java内存模型图文详解

synchronized and lock will have separate chapters to explain the implementation mechanisms respectively. Needless to say, these two are guaranteed in terms of visibility and atomicity. Volatile only guarantees the visibility of data. Only when the data is read and loaded, the data changes in other threads will be sensed in the current thread. If you pass these two stages, you can only be embarrassed. The data Inconsistent, (In fact, what volatile does is to avoid using the cache and not storing the data on the main memory into the thread working memory. In the read and load phases, the data is obtained from the main memory so that other threads can sense the Variable modification). Volatile is just a solution to ensure visibility due to the poor performance of synchronized in early jdk versions. The current jdk version of synchronized and lock has been optimized to a certain extent, so it is generally not recommended to use volatile variables unless you know what you are using volatile for now, because it does not guarantee the correctness of concurrency.

JMM java内存模型图文详解

read and load copies variables from main memory to the current working memory, use and assign executes code, changes shared variable values, store and write refreshes main memory related information with working memory data Content, where use and assign can appear multiple times. volatile is suitable for some idempotent operations. This will be explained in the implementation of lock's nofairsync.

Speaking of this, I have to talk about the principle of happen before. It is a partial order relationship between two operations defined in the Java memory model. If operation A occurs before operation B, it means that before operation B occurs, the impact of operation A can be observed by operation B. , "Influence" includes modifying the value of shared variables in memory, sending messages, calling methods, etc. It basically has nothing to do with the sequence of events in time. This principle is particularly important. It is the main basis for judging whether there is competition in the data and whether the thread is safe.

The following are eight rules in the Java memory model that guarantee happen-before. They already exist without the assistance of any synchronizer and can be used directly in coding. If the relationship between two operations is not in this list and cannot be deduced from the following rules, they have no order guarantee, and the virtual machine can randomly reorder them (in order to fully utilize the CPU and improve utilization, the jvm , JVM will reorder irrelevant codes or operations, so that operations that need to wait for IO or other resources are placed at the back, while other operations that can be completed instantly are placed at the front and executed first, making full use of CPU resources) .

1. Program sequence rules: In a separate thread, according to the execution flow sequence of the program code, the operation performed first (in time) happens—before the operation performed later (in time).

2. Management locking rules: an unlock operation happens—before (in time sequence, the same below) a lock operation on the same lock.

3. volatileVariable rules: A write operation on a volatile variable happens—before a subsequent read operation on the variable.

4. Thread startup rules: The start() method of the Thread object happens—before every action of this thread.

5. Thread termination rules: All operations of the thread happen—before the termination of this thread is detected. The thread can be detected through the end of the Thread.join() method, the return value of Thread.isAlive(), etc. Execution has been terminated.

6. Thread interruption rules: The call to the thread interrupt() method happens—before the event occurs when the code of the interrupted thread detects the interruption.

7. Object termination rules: The initialization of an object is completed (constructorends execution) happens—before the start of its finalize() method.

8. Transitivity: If operation A happens—before operation B, operation B happens—before operation C, then we can get A happen—before operation C.

The above is the detailed content of Detailed graphic explanation of JMM java memory model. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn