I am a recently by autumn recruit to pieces of Java small white, after experienced autumn recruit, realize the importance of the JVM virtual machine, although know the virtual machine before some of the basic knowledge and concepts, but for bagging this into the giant’s heart I is not enough, so want to further understand and study the JVM, The book “Deep Understanding of JAVA Virtual Machine” is very clear about the anatomy of JVM. I have been reading it recently. I have summarized some very good things in my opinion.

JVM memory structure and memory overflow situations

Java runtime data area

The program counter, virtual machine stack, local method stack is the thread private memory method area, and the heap is the thread shared data areaCopy the code

1) Program counter A program technician is a small memory space that can be seen as a line number indicator of the bytecode executed by the current thread. Change the value of the bytecode interpreter to determine which bytecode instructions need to be executed for the next hop. JVM multithreading is implemented by taking turns switching and allocating processor execution time. A processor (one core of a multi-core processor) executes instructions in only one thread. Each thread has a separate program counter. Records the JVM bytecode specified address being executed when a Java method is executed. The counter is empty when the native method is executed.

The JVM does not specify any OutOfMemortError in this area.Copy the code

2) Virtual stack lifecycle is the same as thread, describing the memory model of Java method execution. When the method is executed, a stack frame is created to store the local variable table, operand stack, dynamic link, method exit and other information. The method is called from the beginning to the completion of the call, corresponding to the stack frame on to off the stack. The local variable table holds basic data types known at compile time, references to objects, and returnAddresses (addresses pointing to a bytecode instruction). 64-bit long and double stand in two local variable Spaces and one for the rest. The memory space of the local variable table is determined by the compiler and does not change at run time.

StackOVerFlowError is reported when a thread requests a stack depth larger than specified by the JVM. OutOfMemoryError is reported when the stack cannot allocate sufficient memory during dynamic expansionCopy the code

3) Local method stack Implement Native method Sun HotSpot integrate virtual machine stack and local method stack

The exception is the same as that of the VM stackCopy the code

The Heap is the area of the JVM that occupies the largest amount of memory. It does not require contiguous memory space and is created at JVM startup. The heap is used to hold object instances. The main administrative area of the garbage collector, also known as the GC heap. Since mainstream virtual machines use generational collection, the heap can be divided into new generation and old generation. The heap shared by threads can also be divided into multiple Thread local Allocation Buffers (TLabs).

OutOfMemoryError is reported if there is no memory in the heap to complete the instance allocation and no further expansion is possibleCopy the code

5) The method area is used to store class information that has been loaded by JVM, constants, static variables, and even compiled code. Method areas are initially implemented by persistent generations, which are more prone to early memory overflow. After jdk1.7, the string constant pool was removed from the permanent generation. After jdk1.8, the permanent generation was removed and metaSpace introduced. Method areas do not require contiguous memory space, are extensible, and do not require garbage collection.

OutOfMemoryError is reported when the method area cannot meet memory allocation requirementsCopy the code

6) The runtime constant pool holds various literal and symbolic references generated at compile time, as well as translated direct references. The runtime constant pool is stored in the method area after the class is loaded. New constants can be pooled at run time, such as the intern method of String. (See my other String blog post here.)

An OutOfMemoryError is reported when the constant pool cannot allocate any more memoryCopy the code

Object creation process

1) When the JVM receives a new instruction, it checks whether the corresponding symbolic reference can be found in the constant pool for the parameter carried by the instruction, and then checks whether the corresponding symbolic reference has been loaded. If not, the advanced class is loaded. 2) After the class loading is completed, the memory of the object is allocated, and the required memory of the object is completely determined after the class loading.

  • There are two ways to allocate memory:
  • Pointer collision When heap memory allocation is very regular (that is, free memory and used memory are completely separated by a pointer), the allocation of memory only moves the pointer to the free side equal to the size of the object.
  • Free list If memory is allocated improperly, the JVM maintains a list of available memory and allocates a large enough chunk of memory to objects.
  • Whether the heap memory is organized depends on whether the garbage collector has collation capabilities
  • The thread-safe solution to memory allocation synchronizes the memory space allocation: CAS+ retry on failure ensures atomicity of the update operation. The act of allocating memory into different Spaces by thread: allocate local thread allocation buffers (TLabs) for each thread.

3) After allocating memory, initialize the allocated memory space to zero value (excluding the object header) to ensure that the object instance can be used directly without assigning initial value. 4) Set the object header. 5) Execute init method after new instruction.

Object header layout: object header, instance data, and its padding.

  • 1) : Object header runtime data of the object itself, including HashCode, GC generation age, lock status flag, thread holding lock, biased process ID, biased timestamp, etc. Type pointer: The JVM uses a pointer to determine which class the object is an instance of. If the object is an array, the object header records the size of the array, because the size of the array cannot be obtained from the object metadata.
  • The contents of various types of fields defined in the instance data code, including those inherited from a parent class.
  • There is no special meaning for its padding. Placeholders work because the JVM specifies that the object’s starting address must be a multiple of 8 bytes, and the object’s header size is exactly that.

Object access location

Java programs can use reference data on the stack to manipulate specific objects in the heap in either of two ways: using handles, direct Pointers ** handles: **heap divides a block of memory as a handle pool, and Reference stores the address of an object’s handle, which contains the address information of object instance data and object type data.

Direct Pointers: Reference stores the address of an object

The advantage of using a handle is that there is no need to change the reference when the object needs to be moved. Only the instance data pointer in the handle is changed. The direct pointer is fast and saves the time cost of a pointer location

Garbage collection and memory allocation policies

What is GC? Why GC?

GC is garbage collection, memory is the programmer is more prone to problems, forget or wrong memory collection will lead to program or system instability or even crash, Java provides GC function can automatically detect whether the object is out of scope and achieve the purpose of automatic collection. Program counters, virtual machine stacks, and local method stacks grow and die with threads. Memory allocation and reclamation in these three areas are deterministic. When a method terminates or a thread terminates, memory is naturally reclaimed. The memory allocation of the heap and method areas is dynamic and therefore requires a garbage collection mechanism. Determine if an object is dead: An object that can no longer be used in any way is dead.

Briefly describe JAVA’s GC mechanism

In Java, the programmer does not have to manually free the memory of an object, but the JVM does it itself. In the JVM, there is a low-priority garbage collection thread that normally does not execute, but is triggered only when the JVM is idle or out of memory, scanning for objects that do not have any references and adding them to the collection for collection.

There are ways to tell if an object is deadReference counting algorithmandAccessibility analysis algorithm

1) : The reference counting algorithm adds a reference counter to the object. Whenever there is a reference to the object, the counter +1, the reference is invalid, and the counter -1 at any time the object whose counter is 0 is an object that can no longer be used, and the object is considered dead. But reference counters are difficult to solve for objects that refer to each other in a loop

2) : Reachability analysis algorithm Mainstream languages use reachability analysis algorithm to judge whether the object is alive or not. When there is no reference chain between an object and GC Roots (i.e., GC Roots is unreachable to the object), it proves that the object is unusable and will be judged as a recyclable object. Can be used as an object for GC Roots

Object referenced in method area of virtual machine stack (local variable table of stack frame) object referenced in method area of static attribute object referenced in constant object referenced in JNI (generally referred to as Native) object referenced in local method stackCopy the code

reference

Prior to JDK1.2, if the value of a reference datastore represented the starting address of another chunk of memory, the chunk represented a reference. After jdk1.2, references are divided into strong references, soft references, weak references, and virtual references

  • Strong references: common in code such as “Object obj = new Object()”. As long as strong references exist, the Object will never be recycled.
  • SoftReference: an object that is useful but not required. The JVM allocates the object to be reclaimed before it runs out of memory. If there is still not enough memory left after the collection, an out-of-memory exception is thrown.
  • WeakReference: describes non-essential objects, which are weaker than soft references. Objects associated with soft references can only survive until the next garbage collector execution, regardless of whether there is enough memory, will be reclaimed. After jdk1.2, weakReference is used to achieve weakReference.
  • Virtual reference: the weakest reference relationship, does not affect the lifetime of the object, and cannot obtain the object instance through virtual reference. The only function is to receive notification from the system when the object is reclaimed.

Two marks that declare an object dead

1) It is found that the object is not connected with GC Roots after the reachabability analysis. The first labeling and first filtering conditions are to determine whether it is necessary to implement Finalize method for the object. If the object has not overwritten Finalize method or the JVM has called finalize method, If deemed necessary, the object is placed in an F-queue and the JVM automatically creates a low-priority Finalizer thread to execute. This means that the JVM can only ensure that the thread is started. However, the completion or success of thread execution cannot be guaranteed because if the Finalize method of an object executes very slowly or an infinite loop occurs, other objects will wait for a long time, or even the whole memory will crash. 2) Later GC makes a second mark on f-queue. If the object is connected with GC Roots at this time, the collection of objects to be reclaimed will be removed; otherwise, it will be reclaimed.

Finalize method of any object can only be called once, and Finalize method is not a destructor of C or C++, which is very expensive to run and has large uncertainties. Therefore, it is impossible to guarantee the call order of objects. Try-finally can be better.

Recovery method area

The JVM can dispense with requiring garbage collection in the method area, where it is “cost-effective.” Garbage collection of the permanent generation mainly includes: discarded constants, useless classes

  • Deprecating a constant is similar to recycling an object from heap
  • The java.lang. class object of the class is not referenced anywhere and cannot be reflected anywhere to load the method of the class

Garbage collection algorithm

The most basic: mark-clear algorithm is divided into two phases of mark and clear insufficient

  • Low efficiency
  • Space (large number of discontinuous memory fragments after flag clearing)

The replication algorithm divides memory into two equal areas and uses only one of them at a time. When one area of memory is used up, the surviving objects are copied to the other area and the used memory space is cleaned up at a time. At the cost of reducing memory by half.

HotSpot divides the memory into a larger Edeh space and a cooler Servivor space. When Servivor=8:1 is recovered, the surviving objects in Eden and Servivor will be copied to another Servivor at a time, and the Eden and Servivor used will be cleared at last. However, it cannot be guaranteed that no more than 10% of the objects will survive each time. When Servivor is insufficient, Rely on other memory space (old age), which is required to allocate guarantees.

Tag – sorting algorithm to take when the object replication algorithm surial more copy operation, low efficiency, use in old age – sorting algorithm marking process – clear algorithm is consistent with the markers Subsequent steps are not directly to recyclable objects to clean up, but let all live objects move to the end, and then directly to remove the boundaries of memory.

The generation collection algorithm divides the heap into new generation and old generation according to the period in which the object is stored

  • Every time in the new generation a large number of memory die, only a few memory can survive, choose the replication algorithm
  • In the old age, the survival rate of objects is higher, so the mark-clear algorithm or mark-tidy algorithm is used

HotSpot algorithm implementation

Enumeration and node reachability analysis will consume a lot of time to find the reference chain from GC Roots. The sensitivity of the reachability analysis to the execution time is also reflected in the GC pause. During the whole analysis process, the object reference relationship should not change during the analysis. Currently, the JVM used is accurate GC. After the execution system stops, it does not need to check all execution contexts and global reference locations. In HotSpot, a set of OopMap data structures are used. When the class is loaded, HotSpot records which offsets in the object correspond to which types and, during JIT compilation, which locations in the stack and registers are references.

OopMap allows HotSpot to do GC Roots enumerations quickly and accurately, but if every instruction calls OopMap, it requires a lot of extra space, and GC space costs go up, so HotSpot only generates the selected base of OopMap safe points on the safe points: The most obvious feature of “long execution” is the reuse of instruction sequences (such as method calls, loop jumps, exception jumps, etc.).

How do I make a thread pause at a safe point during GC

  • Rescue interrupt: When GC occurs, all threads are interrupted. If any thread is found to be out of the safe point, the thread is resumed until it reaches the safe point.
  • Active interrupts: GC sets a round-robin flag at checkpoints and where memory needs to be allocated to create objects. The thread actively rounds this flag while executing and suspends its own interrupt if it finds an interrupt request true.

The softPoint security zone ensures that a program execution will encounter a softPoint that can enter the GC within a short period of time. However, when a thread is not allocated CPU resources, such as a thread in the sleep state, it cannot respond to interrupt requests from the JVM. Safe Region refers to a piece of code in which the reference relationship does not change. When a thread executes into a Safe Region, it first identifies that it has entered the Safe Region. When the JVM makes a GC request, Never mind that when a thread of code in the Safe Region leaves the Safe Region, it checks to see if the node enumeration is complete or the GC is complete. If so, the thread continues execution, otherwise it waits for a signal that it can leave the Safe Region to continue execution.

The rationale for garbage collector? Can it be recycled immediately? Can you manually tell the JVM to do gc? In the case of GC, when a programmer creates an object, the GC starts monitoring the address, size, and usage of the object, and typically the GC records and manages all objects in the heap in a directed graph. This is a way to determine if an object is “reachable,” and if the GC determines that it is not, the GC reclaims the memory space. You can manually execute system. GC to tell the GC to run, but the Java language does not guarantee that the GC will execute.

If the object reference is set to NULL, does gc execute immediately? No, this object can be reclaimed in the next GC cycle

What is Distributed Garbage Collection (DGC) and how does it work? DGC is called distributed garbage collection, and RMI uses DGC for automatic garbage collection because RMI contains references to remote objects across JVMS. Garbage collection is difficult. DGC uses reference technology algorithms to provide automatic memory management for remote objects.

Garbage collector

Parallelism and concurrency

Concurrent: Multiple garbage collection threads work in parallel, but the user is still in the waiting state. Concurrent: The user and the garbage collection thread execute simultaneously, not necessarily in parallel, but alternatelyCopy the code

1) Serial collector

  • A single-threaded collector, which uses only one CPU or one hand collection thread, must suspend all worker threads until the collection is complete
  • Simple and efficient (compared to other collectors with single threads)
  • Serial is a good choice for JVMS running in client mode

2) ParNew collector

  • ParNew is the multithreaded version of Serial
  • Is the next-generation collector of choice for many JVMS running in Server mode
  • Only Serial and parNew can work with the CMS
  • The number of collection threads enabled by default is the same as the number of cpus

3) Parrller Scavenge

  • Parallel, new generation collector, using copy algorithm
  • The goal is to achieve a manageable throughput (user code time in CPU run/total CPU consumption time)
  • Ideal for tasks that compute in the background without much interaction

4) Serial Old collector

  • An older version of Serial, single-threaded, uses a mark-collation algorithm
  • For use by JVMS in client mode

5) Paraller Old collector

  • multithreading
  • Use a mark-de-clutter algorithm
  • Used in the old days
  • Available after JDK1.6
  • Paraller Scavenge+Paraller Old is preferred for applications with sensitive throughput and CPU resources

6) CMS collector – the collector that aims at obtaining the shortest recovery time is suitable for the application that attaches importance to the corresponding time of the service and the shortest system pause using the four stages of the mark-clear algorithm CMS

  • Initial tagging: Tagging only objects that GC Roots can contact directly is fast
  • Concurrent tags for GC Roots Tracing
  • Re-marking is to correct the mark record of the part of the object where the mark changes because the user is almost working during concurrent marking
  • Concurrent remove
  • Concurrent tagging and concurrent cleanup can work with user threads

The disadvantage of the CMS

  • CMS is very sensitive to CPU resources. Although it does not cause user threads to pause, it may slow down user processes and reduce throughput because some thread resources are occupied
  • CMS cannot handle floating garbage
  • Because CMS uses the “mark-sweep” algorithm, a large amount of space debris will be generated after collection

7) G1 collector service oriented garbage collector, applied in multi-core processor and large capacity memory environment, in the realization of high throughput at the same time, as far as possible to meet the garbage collector’s pause time request to CMS can be concurrent with the application of G1 compared with CMS advantages

  • The G1 garbage collector is a garbage collector with a defragmenting memory procedure that does not generate much memory fragmentation
  • G1’s Stop the World is more controllable, with a predictive mechanism added to pauses that allows users to specify a desired pause time
  • G1 divides the entire heap into independent regions of equal size, preserving the concepts of Cenozoic and old-age, but no longer being physical partitions
  • G1 can make full use of CPU, multi-core environment hardware advantages, minimize STW
  • G1 uses a mark-collation algorithm for the whole and a copy algorithm for the parts without memory fragmentation
  • G1 has no physical Cenozoic or old age

G1 Recovery Procedure

  • Initial markup: Marks objects that GC Roots can directly associate with, which takes a long time to pause the thread
  • Concurrent marking: Start from GC Roots to analyze the reachability of objects in the heap and find out the surviving objects, which takes a long time but can be executed concurrently with the program
  • Final markup: Modifies the factors that cause markup to change as user programs continue to run during concurrent markup
  • Filter collection: Sort the collection value of each region and specify a collection schedule based on the expected GC pause time of the user

Object memory allocation

If the Local Thread Allocation Buffer is enabled, the Buffer is allocated to the TLAB by Thread priority. TLAB (Thread Local Allocation Buffer) : In rare cases, the Buffer is allocated to the old age directly

  • In most cases, objects are allocated in Eden of the new generation. When Eden does not have enough space for allocation, the JVM initiates Minor GC.
  • Large objects enter the old age directly (parameter: -xx: PretenursSizeThreshold) Large objects refer to Java objects (such as arrays or long strings) that require a large amount of contiguity memory space Large objects are placed in the old age to prevent extensive memory replication between Eden and two Servivor regions
  • The JVM defines an object age counter for each object. If the object survives after Eden’s birth and passes through the first minor GC, it can be accepted by Survivor, and is moved to Servivor, and the object is of age 1. Each time the object survives the first minor GC, the age +1, Increased to the old age promotion threshold (default: 15), will be promoted to the old age, can be adjusted by (-xx: MaxTenuringThreshold)
  • If the sum of objects of the same age in Servivor is more than half of Servivor, objects older than or equal to this age can enter the old age

Before a minor GC occurs, the JVM checks whether the largest contiguous space in the old generation is greater than the total space of all objects in the new generation. If so, the JVM checks whether HandlePromotionFailure is allowed. Continue to check if the maximum contiguous space available for the old age is greater than the average size of the objects promoted to the old age. If so, try Minor GC, but there is a risk that if not, or HandlePromotionFailure does not allow the guarantee to fail. The risk is that HandlePromotion is no longer used after Full GC JDK1.6, and the guarantee is allowed to fail by default

A memory leak is a condition in which an object or variable that is being reused remains in memory

  • Long-life objects holding references to short-life objects can cause memory leaks, such as in caching systems
  • The cache system loads an object into the cache, and then it’s never used, and the object is always cached, but it’s never used again
  • When an object is put into a HashSet, changing the parameters used in the object to compute the Hash will cause the current object to be unable to be removed from the HashSet alone, causing a memory leak.

What is the use of system. gc and Runtime.gc to prompt the JVM for garbage collection, but whether to start it immediately or delay it depends on the JVM

Java class loading mechanism

Java loads the data describing the class from the class file into memory, and verifies, converts, parses, and initializes the data to form a Java type that can be directly used by the JVM. Rather, it ensures that the underlying classes in which the program runs are fully loaded into the JVM and that other classes are loaded as needed, providing a high degree of flexibility for Java applications.

Classes start when they are loaded into JVM memory and end when they are unloaded

The lifecycle includes: load, validate, prepare, parse, initialize, use, unload

Validation, preparation, and parsing are the three parts of the connection

The load, prepare, and parse parts are called connections

Load, validate, prepare, initialize, unload order is determined, and in some cases parsing may occur after initialization

These phases are usually interleaved, with one phase usually activating another phase during execution

Five cases in which initialization is performed

  • When new, getstatic, putstatic, invokestatic is encountered, if the class is not initialized, you need to trigger the initialization first. When using the new instance class object, read or set the static field of the class. Static methods are already called by the compiler on static fields that put the result into the constant pool
  • When a reflection call is made to a class using the java.lang.Reflect package’s methods, the class needs to be initialized first if it is not already
  • When initializing a class, initialize the parent class first if the parent class is not initialized
  • When the JVM starts, the user specifies an execution main class (the class that contains the main method), which Java initializes first
  • Using jdk1.7 dynamic statement support, if a Java. Lang. Invoke. Finally the interpretation of the results for REF_getstatic MethodHandle instance, REF_putstatic, REF_invokestatic method handles, If the class corresponding to this handle is not initialized, initialization is triggered first
  • These five become active references, and all other ways of referring to a class do not trigger initialization and become passive references
  • The loading process of an interface is different from class loading
  • Interfaces cannot use static code blocks
  • In interface initialization, the parent interface is not required to complete serialization, only when the parent class is actually used (for example, referencing constants defined in the interface) is initialized

The process of class loading

1) load

  • Load the Java bytecode as a binary stream, read it into memory, place it in the method area of the runtime data, and create a Java.lang.Class object describing the data structure of the Class
  • You can load class files from disk JARS, wars, networks, and your own class files

2) verification

  • Ensure that the class load is correct and that byte streams of the class file do not affect JVM security validation
  • File format verification: for example, verify the JDK version represented by the magic number at the beginning of the file, whether there are unsupported constants in the constant pool, etc
  • Metadata validation: verifies that a class has a parent class, inherits classes that are not allowed to inherit, implements methods that are required in the parent class or interface, etc..
  • Bytecode validation: Method validation of a class to ensure that the type conversion is correct
  • Symbolic reference validation: Occurs when a symbolic reference is converted to a direct reference to ensure that the symbolic reference can find the corresponding main class
  • If the validation fails, VerifyError is thrown and the binary stream in memory is put into the method body of the JVM’s run data area

3) to prepare

  • Allocates memory for static variables of the class and initializes them to default values

4) parsing

  • Convert symbolic references in the virtual machine constant pool to direct references

5) Initialization

  • Passive use does not result in class initialization
  • To assign an initial value to a static variable, execute the static block
  • Class initialization method, called the first time the JVM loads the class file
  • Instance initialization method, instance created by using the call

Class loader

Class loaders are used to implement the loading action of a class. Each class needs to be unique in the Java virtual machine by the classloader that loads it and the class itself. Each loader has a separate class namespace

Scope of classloader responsibility

  • BOotStrap classloader is not a Java class. It is implemented in C++ and is responsible for loading the JDK core libraries at Java startup. It is fully controlled by the JVM
  • Extension classLoader Is a common Java class inherited from the classloader class. Extension classloader is responsible for loading all JAR packages under jre/lib/ext
  • App ClassLoader Extension A child object of the classloader, responsible for loading all jar and class files in the application classpath

There are two loading modes

  • ClassForName: To ensure that a Java class is loaded into memory, the default class initialization is to execute the internal static code block to ensure that the static attribute initialization, the default use of the current class loader to load the corresponding class
  • This. LoadClass: Because of the parent delegate, the BootStrap ClassLoader eventually loads the. Class file into the JVM. Static blocks are executed only at newInstance.

Parental delegation model

Parent delegation means that each time a class load request is received, the request is first delegated to the parent ClassLoader (all loaders are eventually delegated to the top-level BootStrap ClassLoader). If the parent ClassLoader fails to complete the load (the loader does not find the corresponding class in its search scope), the subclass tries to load by itself. If none is found, report ClassNotFoundException.

Why parent delegate

  • To avoid reloading, Java classes have a hierarchy of priorities with their classloaders (or directories), which is important for the stable operation of Java programs.

Break the parental delegation model

After jdk1.4, mysql registers the Driver

Get com.mysql.jdbc.driver full Class name class.forname loadCopy the code

Analyze the CLassFormat loading using the caller’s CLassLoader, while caller DriverManager is the total loader in the re.jar package, CLassLoader is the CLassLoader, Com.mysql.jdbc.driver is not in

/lib, so it is impossible to load the mysql class. This is a limitation of the parent delegate model. The parent loader cannot load classes in the child classloader’s path. Then the application must be loaded in the boot class loader, which is called the thread context loader. Thread context loader Thread context class loader can Thread. SetContextClassLoaser () method is set up, if not special setup can be inherited from the parent class, and is generally used by default application class loaders, obviously, The thread-context classloader allows the parent class loader to load classes by calling the child class loader, breaking the principle of the parent delegate model

HotSwap implemented in JAVA hot deployment

Hot deployment is two ways to automatically detect Class changes and update the runtime Class behavior to implement hot deployment without restarting the JVM

  • Modify the JVM source code to change the classloader loading behavior so that the JVM can listen for class file updates and reload the class
  • Create a custom classloader to load classes to listen on

steps

  • Destroy custom classLoader (classes loaded by this loader are automatically unloaded)
  • Update the class
  • Use the new Classloader to load the class

Custom loader

  • Override the findClass method by inheriting java.lang /CLassLoader
  • To comply with parental delegation, override classFind methods
  • To break the parent delegate, override the loadClass method

Java memory model and threads

Java Memory Model (JMM)

  • The goal of the Java memory model is to define access rules for variables in a program that do not include local variables and method parameters because these are thread private.
  • Java memory model regulation all variables in the main thread, each thread has its own working memory, working memory holds the variables used by the thread to wish memory copy of a copy of the thread of variables all the operations must be done in working memory, cannot read and write directly to variables in memory, between different threads cannot directly access the other variables in the working memory, The transfer of variable values between threads is done through main memory.

Memory swap operation

Copying a variable from main memory to working memory, or synchronizing variables from working memory to main memory, ensures atomicity

  • Lock: scoped primary memory variable, representing a variable as a thread-exclusive state
  • Unlock: Scope main memory variable. It releases a variable that is in a locked state before it can be locked by another thread
  • Read: Acts on a variable in main memory, transferring the value of a variable from main memory to the thread’s working memory for subsequent load operations
  • Load: Applies to variables in working memory, placing the variables obtained from main memory by the read operation into a copy of the variables in working memory
  • Use: applied to working memory: Passes the value of a variable in working memory to the execution engine, which executes whenever the virtual machine reaches a bytecode instruction that uses the value of the variable
  • Assign to working memory: Assigns a value received from the execution engine to a variable in working memory. This operation is performed whenever the JVM encounters a bytecode instruction that assigns a value to the variable
  • Store: variable applied to working memory that transfers the value of a variable in working memory to main memory for subsequent write operations
  • Write acts on variables in main memory, putting the values of variables obtained from working memory by store operations into variables in main memory

Rules for performing the above operations

  • A single read and load, store and write operation is not allowed, that is, a variable that has been read from memory but not accepted, or a write back from working memory but not accepted by main memory
  • A thread is not allowed to discard its most recent assign operation, that is, after a variable has changed in working memory, it must synchronize the change to main memory
  • A thread is not allowed to synchronize data from the thread’s working memory to main memory for no reason
  • A new variable can only be created in the main memory. It is not allowed to use an uninitialized variable in the working memory. That is, the assign and load operations must be performed before the use and store operations are performed on a variable
  • A variable can be locked by one thread at a time, but the lock can be repeated by the same thread. A variable can be unlocked only if it has been unlocked for the same number of times
  • Locking a variable clears the object’s value from working memory. Before the execution engine can use the variable, load and assign operations need to be performed again to initialize the value of the variable
  • A variable implementation that has not been locked by a lock operation is not allowed to perform unlock, nor is it allowed to unlock a variable that has been locked by another thread
  • Before you can unlock a variable, you must first synchronize it to main memory (store, write)

Volatile

Shared variables that are volatile: Ensuring visibility of operations on this variable by different threads prohibits instruction reorderingCopy the code

JMM

The JVM defines a Java Memory Model (JMM) that blocks out differences in memory access across hardware and operating systems, allowing Java to achieve consistent memory access across platforms. The JMM is built around dealing with atomicity, visibility, and order in concurrency. Can resolve cache inconsistencies

Atomicity makes an operation uninterruptible, either all executing or all failing, even in a multithreaded environment where an operation once started cannot be disturbed by other threads.

  • The change of a variable is independent of the variable itself
  • Variables do not need to participate in invariant constraints with other state variables

order

  • Synchronized: The semantics mean that only one thread can acquire the lock at the same time, the current lock is occupied, and other threads can only wait. Therefore, synchronized semantics means that threads can only perform “serial” when accessing and reading shared variables, so synchronized has order
  • Volatile: JMM instructions are reordered by the compiler and processor for performance optimization. Java’s natural ordering can be summed up as follows: All operations are ordered if observed in one thread. If one thread observes another, all operations are not required
  • Volatile, on the other hand, disallows instruction reordering and is therefore ordered

Visibility refers to one thread to modify a Shared variable, other threads can immediately get this refers to the JMM by modified will be the new value in the variable synchronous back into main memory, before the variable is read from main memory refresh a variable’s value realization and volatile this way to ensure the new values can be immediately synchronized to the main memory, and can immediately before each use refresh from the main memory, Volatile guarantees that visible rows synchronized and final also have visible rows

  • Synchronized Before you can unlock a variable, you must first synchronize it back to main memory
  • Final: The value of a final field can be seen by other threads once the constructor has initialized the field and the constructor does not pass a reference to “this”

The happens-before principle

The main criterion for judging whether data is competing and whether thread is safe is based on the principle of prior occurrence. It means that if operation A precedes thread B, the influence of operation A can be observed by operation B. The influence refers to modifying the value of shared variables in memory, sending messages and calling methods

Happens-before as stipulated by JMM

  • Sequence rule: In a thread, in order of program code, operations written earlier take place before those written later
  • Manage locking rules: An UNLOCK operation is performed first by a subsequent lock operation on the same lock
  • Rule for volatile Variables: Writes to a volatile variable occur before reads to that volatile variable
  • Thread start rule: The start method of the Thread object occurs first for each action of the thread
  • Thread termination rule: All operations in a thread are preceded by termination detection for that thread
  • Thread interrupt rule: A call to the threadinterrupt method occurs before code in the interrupted thread detects the occurrence of an interrupt event
  • Object finalization rule: The finalization of an object happens first at the start of its Finalize method
  • Transitivity: if A precedes B and B precedes C, then A precedes C