Detailed explanation of JVM in one article

Detailed explanation of JVM

Recently I have studied: Zhou Zhiming's "In-depth Understanding of High Concurrency Programming" ;;
Hereby I briefly summarize some of the learning to facilitate the subsequent improvement and consolidation of JVM-related knowledge;
if you want to learn more about the learning, you can read the above reference original work;

Java memory area and OOM

Runtime data area

When the Java virtual machine executes a Java program, it divides the memory space it manages into several different data areas.

These areas have their own purposes, creation and destruction times

The memory managed by the Java virtual machine will include the following runtime data areas:

Insert image description here

  1. program counter

    A smaller memory area that can be viewed as a line number indicator of the bytecode executed by the current thread.

    In the virtual machine conceptual model, the bytecode interpreter selects the next bytecode instruction to be executed by changing the value of this counter.

    Since Java virtual machine multi-threading is implemented by switching threads and allocating CPU time slices; at any given time, a processor (or a core of a multi-core processor) will only execute instructions in one thread. Therefore, in order to restore the correct execution position after thread switching, each thread needs a private counter ; the counters of each thread do not affect each other and are stored independently.

    Notice:

    ​ If a Java method is executed, the value of this counter is the virtual machine bytecode instruction address;

    ​ If the Native method is executed, this value is empty;

    ​ This area is the only area where the OOM situation is not specified in the virtual machine specification;

  2. java virtual machine

    The Java virtual machine is also thread-private and has the same life cycle as the thread;

    The virtual machine stack describes the memory model of Java method execution: a stack frame is created when each method is executed, which is used to store local variable tables, operand stacks, dynamic links, method exits and other information.

    The process from the call to the completion of execution of each method corresponds to the process of a stack frame from being pushed into the stack to being popped out of the virtual machine stack;

    The local variable table stores various basic data types and object references known to the compiler ; the memory space required by the local variable table will be allocated after the compilation period is completed;

    In the Java virtual machine specification, this area specifies two exceptions that can occur:

    1. StackOverflowError: The stack depth requested by the thread is greater than the virtual stack depth allowed;

    2. OutofMemorryError: Most virtual machine stacks can be dynamically expanded. If sufficient memory cannot be applied for during expansion, this exception will be thrown;

  3. native method stack

    The effect on the virtual machine stack is similar, the biggest difference is:

    The virtual machine stack executes Java method services for the virtual machine, while the local method stack executes Native method services for the virtual machine ;

    Since the virtual machine specification does not mandate local method stacks, specific virtual machines can be implemented freely. Some virtual machines (such as Sun Hotspot) directly combine the local method stack and the virtual machine stack into one;

    The local method stack is similar to the virtual machine stack and will also throw StackOverflowError and OutofMemorryError;

  4. java heap

    For most applications, the Java heap is the largest piece of memory managed by the virtual machine;

    The Java heap is a memory area shared by all threads and is created when the Java virtual machine starts ;

    The only purpose of this memory area is to store object instances , and almost all object instances allocate memory here;

    The Java heap is the main area managed by the garbage collector ;

    From the perspective of memory recycling, since current collectors adopt generational collection algorithms, the Java heap can also be subdivided into: new generation and old generation;

    To be more detailed, it can be divided into: Eden area, From Survivor area, To Survivor area, etc.;

    The purpose of such further subdivision is: to better reclaim memory or allocate memory faster;

    According to the Java virtual machine specification, the Java heap can be in physically discontinuous memory space, as long as it is logically continuous;

    If there is no memory in the heap for instance allocation and the heap cannot be expanded, an OutofMemoryError exception will be thrown;

  5. method area

    The method area, like the Java heap, is a memory area shared by each thread;

    Used to store data such as class information, constants, static variables, code compiled by the just-in-time compiler, etc. that have been loaded by the virtual machine ;

    The Java virtual machine specification has very loose restrictions on the method area. In addition to not requiring continuous space like the heap and having the option of fixed size or expandability,

    You can also choose not to implement garbage collection.

    Garbage collection behavior is relatively rare in this area. Memory recycling in this area is mainly for the recycling of constant pools and unloading of types;

    According to the Java virtual machine specification, when the method area cannot meet the memory allocation requirements, an OutofMemoryError exception will be thrown;

  6. Runtime constant pool

    The runtime constant pool is part of the method area;

    In addition to descriptive information such as the class version, fields, interfaces, methods, etc., the Class file also has a constant pool , which is used to store various literals and symbol references generated during compilation. This part of the content will be loaded when the class is loaded. After that, enter the runtime constant pool in the method area ;

    Another feature of the runtime constant pool for the Class file constant pool is that it is dynamic :

    The Java language does not require that constants must be generated during compilation, that is, the contents of the constant pool that are not preset in the Class file can enter the runtime constant pool; constants may also be put into the pool during runtime; this feature is exploited The most common one is the intern() method of the String class;

    (After calling intern(), first check whether there is a reference to the object in the string constant pool . If it exists, return the reference to the variable, otherwise add the reference and return it to the variable)

  7. direct memory

    Direct memory is not the virtual machine runtime data area, nor is it the memory area defined in the Java virtual machine specification, but this part of memory is also frequently used and may also cause an OutofMemoryError exception;

    Obviously, the allocation of native direct memory will not be limited by the size of the Java heap; but since it is memory, it will definitely be limited by the total memory size of the native machine and the processor addressing space;

    When configuring virtual machine parameters, direct memory is ignored, causing the sum of each memory area to be greater than the physical memory limit, resulting in an OutofMemoryError exception during dynamic expansion;

Actual OutofMemoryError exception

In the Java virtual machine specification, in addition to the program counter, several other runtime data areas have the possibility of OutofMemoryError exceptions. Next, we will verify the exception occurrence scenarios through several examples, and introduce several memory-related virtual machines. parameter;

First introduce a few JVM parameters:

  1. -Xms: Set the JVM initial heap memory size
  2. -Xmx: Set the JVM maximum heap memory size
  3. -Xmn: Set the size of the young generation
  4. -Xss: Set the stack size of each thread
  5. -XX:+HeapDumpOnOutofMemoryError: When an OOM exception occurs, a heap dump file is generated
  6. -XX:HeapDumpPatch=patch: stores the generated heap dump file path; for example -XX:HeapDumpPath=F:\books
  7. -XX:+PrintGCDetails: Print GC detailed information
  8. -XX:+PrintGCTimeStamps: Print GC timestamps
  9. -XX:MetaspaceSize: Set the size of metaspace to trigger garbage collection
  10. -XX:MaxMetaspaceSize: Set the maximum value of metaspace

Actual simulation of OOM exception:

The example codes below are all run based on SUN's Hotspot virtual machine. For different versions of virtual machines from different companies, the parameters and running results may be different;

  1. Java heap overflow

    The Java heap is used to store objects. As long as objects are continuously created and there is a reachable path between GC Routes and objects to avoid the garbage collection mechanism to clear these objects, then after the memory occupied by the object reaches the maximum heap capacity limit, OOM exception will occur;

    In the sample code, the Java heap size is limited to 20M and cannot be expanded (set the minimum value -Xms parameter of the heap and the maximum value -Xmx parameter to be the same to avoid automatic expansion of the heap), and pass the parameters -XX:+HeapDumpOnOutOfMemoryError, -XX: HeapDumpPath=F:\books allows the virtual machine to dump the current heap memory dump snapshot when an OOM exception occurs and save it in the specified location for subsequent analysis;

    In the sample code, we set the virtual machine parameters as follows:

Insert image description here

Sample code:

/**
 * @author Snow
 * Java堆OOM异常模拟
 */
public class HeapOomDemo {
    
    

    static class OomTest{
    
    }

    public static void main(String[] args) {
    
    
        ArrayList<OomTest> oomTests = new ArrayList<>();
        while (true){
    
    
            oomTests.add(new OomTest());
        }
    }
}

Execute the code and the results are as follows:

java.lang.OutOfMemoryError: Java heap space
Dumping heap to F:\books\java_pid11132.hprof ...
Heap dump file created [28150606 bytes in 0.068 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOf(Arrays.java:3210)
	at java.util.Arrays.copyOf(Arrays.java:3181)
	at java.util.ArrayList.grow(ArrayList.java:265)
	at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:239)
	at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:231)
	at java.util.ArrayList.add(ArrayList.java:462)
	at jvm.HeapOomDemo.main(HeapOomDemo.java:16)

It can be seen from the running results that an OOM exception occurred and a dump file was generated under the Dump path configured in our virtual parameters:

Insert image description here

To solve this exception, we need to first analyze the Dumped file through the memory impression analysis tool. Next, we use Java's VisualVm to analyze this file: Command line execution: jvisualvm

Insert image description here

After executing the command, the VisualVm tool will open and we import the previous file:

Insert image description here

After importing and analyzing the Dump file, you can see the following analysis results:

Insert image description here

  1. Virtual machine stack and local method stack overflow

    Since there is no distinction between the virtual machine stack and the local method stack in Hotspot virtual machine, for the Hotspot virtual machine, although the -Xoss (local method stack size) parameter exists, it is actually invalid. The stack capacity is only determined by -Xss Parameter settings.

    For the virtual machine stack and local method stack, the Java virtual machine specification defines two exceptions:

    1. If the stack depth requested by the thread is greater than the maximum depth allowed by the virtual machine, a StackOverflowError exception will be thrown.
    2. If the virtual machine cannot apply for enough memory space when expanding its memory, an OutofMemoryError exception will be thrown.

    In the following example, the experiment is limited to operations in a single thread:

    1. Use the -Xss parameter to reduce the stack memory capacity; result: a StackOverflowError is thrown, and when an exception occurs, the output stack depth is reduced accordingly.
    2. A large number of local variables are defined, increasing the length of the local variable table in this method frame; result: StackOverflowError is thrown, and the output stack depth is reduced accordingly.

    Sample code:

    public class StackSomDemo {
          
          
    
        static class SomTest{
          
          
            private int stackLength = 1;
    
            public void stackLeak(){
          
          
                stackLength ++;
                stackLeak();
            }
        }
    
        public static void main(String[] args) {
          
          
            SomTest somTest = new SomTest();
            try {
          
          
                somTest.stackLeak();
            }catch (Throwable e){
          
          
                System.out.println("stack length:"+somTest.stackLength);
                throw e;
            }
    
        }
    }
    

    Running the sample code, the results are as follows:

    stack length:982
    Exception in thread "main" java.lang.StackOverflowError
    	at jvm.StackSomDemo$SomTest.stackLeak(StackSomDemo.java:9)
    	at jvm.StackSomDemo$SomTest.stackLeak(StackSomDemo.java:10)
    	at jvm.StackSomDemo$SomTest.stackLeak(StackSomDemo.java:10)
    

    The above running results show that: in a single thread, whether due to the stack frame being too large or the virtual machine capacity being too small, when memory cannot be allocated, the virtual machine throws a StackOverflowError exception;

  2. Method area and runtime constant pool overflow

  3. Direct local memory overflow

Garbage collector and memory allocation strategy

Is the subject dead?

Almost all object instances in Java are stored in the heap. Before the garbage collector recycles objects, the first thing is to determine which of these objects are "alive" and which are "dead";

reference counting

That is, add a reference counter to the object. Whenever there is a reference to it, the counter value is incremented by one; when the reference expires, the counter value is decremented by one;

At any time, an object with a counter value of 0 can no longer be used and is counted as a "dead" object.

The reference counting method is simple to implement and has high determination efficiency; however, it is difficult to solve the problem of circular references between objects, so it is rarely used in mainstream virtual machines.

Sample code:

//-XX:+PrintGCDetails,配置此选项打印GC信息
public class RefCountDemo {
    
    
    public Object instance = null;
    public static final int _1MB = 1024*1024;
    /**
     * 占用内存,便于GC日志查看是否被回收
     */
    private byte[] bigSize = new byte[2 *_1MB];

    public static void main(String[] args) {
    
    
        RefCountDemo objA = new RefCountDemo();
        RefCountDemo objB = new RefCountDemo();
        objA.instance = objB;
        objB.instance = objA;

        objA = null;
        objB = null;

        //假设这行发生GC,objA和objB能否被回收
        System.gc();
    }

}

Running the above code, the results are as follows:

[GC (System.gc()) [PSYoungGen: 9359K->728K(153088K)] 9359K->736K(502784K), 0.0007083 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (System.gc()) [PSYoungGen: 728K->0K(153088K)] [ParOldGen: 8K->588K(349696K)] 736K->588K(502784K), [Metaspace: 3116K->3116K(1056768K)], 0.0030812 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
Heap
 PSYoungGen      total 153088K, used 3947K [0x0000000715f00000, 0x0000000720980000, 0x00000007c0000000)
  eden space 131584K, 3% used [0x0000000715f00000,0x00000007162daf90,0x000000071df80000)
  from space 21504K, 0% used [0x000000071df80000,0x000000071df80000,0x000000071f480000)
  to   space 21504K, 0% used [0x000000071f480000,0x000000071f480000,0x0000000720980000)
 ParOldGen       total 349696K, used 588K [0x00000005c1c00000, 0x00000005d7180000, 0x0000000715f00000)
  object space 349696K, 0% used [0x00000005c1c00000,0x00000005c1c93208,0x00000005d7180000)
 Metaspace       used 3161K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 342K, capacity 388K, committed 512K, reserved 1048576K

As can be seen from the above running results, the GC log contains "9359K->728K", which means that the virtual machine did not recycle the above two objects because they referenced each other; it also shows that the current virtual machine does not use reference counting. Determine whether the object is alive.

Reachability analysis algorithm

In mainstream implementations of mainstream commercial programming languages, reachability analysis is used to determine object survival.

The main idea of ​​the reachability analysis algorithm is: use a series of objects called "GC-Roots" as the starting point, and search downward from these starting points. The path traveled by the search is called the "reference chain"; when an object reaches the GC -Roots is not connected to any reference chain (in graph theory terms, the object is unreachable to GC-Roots), then the object is determined to be unusable.

As shown in the example diagram, although objects obj5/obj6/obj7 are related to each other, they are not reachable from GC Roots, so they are determined to be recyclable objects:

Insert image description here

In the Java language, objects that can be used as GC Roots are divided into the following types:

  1. Objects referenced in the virtual machine stack (local variable table in stack frame)
  2. Variables referenced by class static attributes in the method area
  3. Objects referenced by constants in the method area
  4. Object referenced by JNI (generally speaking Native method) in the native method stack
Let’s talk about citations again

After JDK1.2, Java expanded the concept of references and divided references into four types: strong references, soft references, weak references, and virtual references. The strength of these four references gradually weakened:

  1. Strong Reference

    ​ Strong references are similar to "Object obj = new Object()"; objects that are ubiquitous in the code, as long as the strong references still exist, the corresponding objects will be recycled by GC;

  2. Soft Reference

    ​ Soft references are used to describe some useful but unnecessary objects; before an OOM exception occurs in the system, the object pointed to by the soft reference will be recycled twice. If there is still not enough memory, an OOM exception will be thrown.

  3. Weak Reference

    ​ Used to describe non-essential objects; objects associated with weak references can only survive until the next garbage collection occurs.

  4. Phantorn

    ​ Also known as ghost reference or phantom reference, its only function is that when the associated object is garbage collected, there will be a system notification;

life or death

Even in the reachability analysis algorithm, in order for an unreachable object to truly be declared "dead", it must go through at least two marking processes:

  1. If after the object is analyzed for reachability, no reference chain of GC Roots is connected to it, it will be marked for the first time and filtered. The filtering condition is whether it is necessary for this object to execute the finalize() method:
    1. When the object does not cover the finalize() method, or the finalize() method has been called by the virtual machine, this situation is considered "unnecessary to execute".
    2. If the object determines that it is necessary to execute the finalize() method, then the object will enter an F-Queue queue, and will be executed later by a low-priority Finalizer thread created by the virtual machine;
  2. The finalize() method is the last chance for the object to escape the fate of death. Later, the GC will mark the object in the heap F-Queue twice on a small scale. If the object saves itself in the finalize() method - as long as it is connected to the reference chain Just establish an association with any object, such as assigning itself to a class variable or member variable of the object. Then when it is marked for the second time, it will be removed from the "About to be recycled" collection;

Garbage collection algorithm

Mark-and-sweep algorithm

The mark-clear algorithm is the most basic collection algorithm, which is mainly divided into two stages: marking and clearing:

  1. First mark all objects that need to be recycled
  2. After the marking is completed, the marked objects are uniformly recycled

It is called the most basic because subsequent algorithms are based on its ideas and improved to address its shortcomings.

The main shortcomings of this algorithm are:

  1. Efficiency issues, both marking and clearing processes are not very efficient
  2. Space problem, a large number of memory fragments will be generated after the mark is cleared; too many memory fragments may lead to the subsequent need to allocate larger object space.

Unable to find enough contiguous memory and have to trigger another garbage collection action early

Replication algorithm

In order to solve the efficiency problem, an algorithm called "copy" emerged:

​ It divides the available memory into two equal-sized blocks according to capacity, and only uses one of them at a time. When this block of memory runs out, copy the surviving objects to another block, and then clean up the used memory space at once.

Advantages and Disadvantages:

This allows each half area to be recycled every time, and there is no need to consider memory fragmentation when allocating memory. Just move the top pointer on the stack and allocate memory in order. It is simple to implement and efficient to run.

The disadvantage is that this algorithm reduces the memory to half of the original size, which is too expensive.

Note: Commercial virtual machines now use this collection algorithm to recycle the new generation. IBM's special research shows that 98% of the objects in the new generation are "live and die", so there is no need to follow a 1:1 ratio. Divide the memory space, but divide the memory into a larger Eden area and two smaller Survivor areas, and use Eden and one of the Survivor areas each time . When recycling, copy the surviving objects in Eden and Survivor to another Survivor at once, and finally clean up Eden and the Survivor just used .

The default size ratio of Eden and Survivor for Hotspot virtual machine is 8:1 , that is, the available memory space in each new generation is 90% (80% + 10%) of the entire new generation capacity, and only 10% of the memory will be "wasted" ".

The aforementioned 98% of objects that can be recycled is only data in general scenarios. We have no way to guarantee that no more than 10% of objects will survive each recycling. When the Survivor space is insufficient, you need to rely on other memory (here refers to the old generation). ) for distribution guarantee.

Mark-collation algorithm

When the object survival rate is high, the copy collection algorithm will perform more copy operations and the efficiency will become lower. More importantly, if you don't want to waste 50% of the space, you need to have additional space for allocation guarantee to deal with the extreme situation where all objects in the used memory are 100% alive, so this method generally cannot be used in the old generation. algorithm.

According to the characteristics of the old age, someone proposed a "mark-sort" algorithm:

The marking process is still the same as the "mark-clear" algorithm, but the subsequent steps are not to directly clean up the recyclable objects, but to move all surviving objects to one end, and then directly clean up the memory outside the end boundary.

Generational collection algorithm

The current garbage collection of commercial virtual machines all adopts the "generational collection" algorithm. This algorithm mainly divides the memory into several blocks according to the different life cycles of objects. Generally, the Java heap is divided into the new generation and the old generation; in this way, the most appropriate collection algorithm can be used according to the characteristics of each generation.

In the new generation, during each garbage collection, it is found that a large number of objects have died and only a few survive. Then use the copy algorithm, which only needs to pay the copy cost of a small number of surviving objects to complete the collection.

In the old generation, because the object survival rate is high and there is no extra space to guarantee its allocation, the "mark-clean" or "mark-organize" algorithm must be used for recycling.

garbage collector

If the garbage collection algorithm is the methodology of memory recycling, then the collector is the specific implementation of memory recycling;

In the Java virtual machine specification, there are no specific regulations on how the collector implements memory recycling. Therefore, the garbage collectors implemented by different manufacturers and different versions of virtual machines may be very different, and configuration parameters are generally provided for users to adjust according to their own characteristics. and needs, to combine the collectors needed by each era.

The virtual machine that will be discussed here is based on the virtual machine after JDK1.7 Update 14. The collector included in this virtual machine is as shown in the figure below:

Insert image description here

The figure above shows the collectors in 7 that act on different generations. If there is a connection between the two collectors, it means that they can be used together. The region where the virtual machines are located indicates whether they are in the new generation or the old generation.

Before introducing these collectors next, let us make it clear: although we are comparing various collectors, we are not trying to select the best collector. Because so far, there is no best collector, and there is no universal collector, so we only choose the most suitable collector for specific application scenarios.

Serial collector

The Serial collector is the most basic and oldest collector. It was the only collector in the new generation before JDK1.3.

As can be seen from the name, this collector is single-threaded, which not only means that it will use a single CPU and a single thread to perform garbage collection, but more importantly, it must suspend all other work while performing garbage collection. thread until it is collected.

"Stop the world" is automatically initiated and completed by the virtual machine in the background. It will cause all user threads to be stopped within a certain period of time without being visible to the user. This is problematic for many applications. It's unacceptable.

The following figure shows the running process of Serial/Serial Old collection:

Insert image description here

Starting from JDK1.3, the Hotpost virtual machine development team has been committed to eliminating or reducing pauses caused by worker threads due to memory recycling, from the Serial collector to the Parallel collector, to the CMS collector, and even the latest G1 collector. The pause time of user threads continues to decrease, but there is still no way to completely eliminate it (the collector in RTJS is not included here)

So far, the Serial collector is still the default new generation collector for virtual machines running in Client mode; it also has the characteristics of other collectors: simple and efficient. For environments limited to a single CPU, the Serial collector Without the overhead of thread interaction, you can naturally achieve higher single-thread collection efficiency by focusing on garbage collection.

Therefore, the Serial collector is a good choice for virtual machines used in Client mode .

Parnew collector

The Parnew collector is actually a multi-threaded version of the Serial collector. In addition to using multi-threads for garbage collection, other behaviors include all control parameters available to the Serial collector, collection algorithms, Stop the world, object allocation rules, recycling strategies, etc. All the same as the Serial collector.

The schematic diagram of the Parnew/Serial Old collector is as follows:

Insert image description here

In addition to multi-threaded collection, the Parnew collector is also the first-choice new generation collector for many virtual machines running in Server mode; one of the reasons that has nothing to do with performance but is very important is: currently, except for the Serial collector, it is the only one that can be used with Used in conjunction with CMS collector.

During the JDK1.5 period, the Hotspot collector, the first truly concurrent collector, realized that the GC thread and the user thread (basically) ran at the same time for the first time. However, CMS, as the old generation collector, cannot operate in conjunction with the existing Parallel scavenge collector in JDK1.4; therefore, in JDK1.5, when using CMS as the old generation collector, the new generation can only choose Serial or Parnew collection. device.

In a single-CPU environment, the Parnew collector will never have better results than the Serial collector; even due to the overhead of thread interaction , when the Parnew collector is implemented in multi-threads, it does not guarantee 100% performance in a two-CPU environment. 100% better than Serial collector;

Of course, as the number of CPU cores increases, the Parnew collector is still beneficial for effective utilization of GC resources.

Parallel scavenge collector

The Parallel scavenge collector is a new generation collector, a collector that uses a copy algorithm, and a parallel multi-thread collector. It seems similar to the Parnew collector, so what other features does it have?

The difference between the Parallel scavenge collector is that its focus is different from other collectors: collectors such as CMS focus more on shortening the pause time of user threads during GC, while Parallel scavenge focuses on achieving a controllable throughput; the so- called throughput The quantity is: throughput = running user thread time/(running user thread time + running GC thread time)

The shorter the pause time of the user thread, the more suitable it is for programs that need to interact with the user; while high throughput can efficiently utilize CPU resources and is mainly suitable for tasks that operate in the background and do not require interaction with the user;

The Parallel scavenge collector provides two parameters for precise control of throughput:

  1. -XX:MaxGCpauscMillis: Maximum garbage collection pause time, the parameter value is a number of milliseconds greater than 0
  2. -XX:GCTimeRadio: throughput size, the parameter value is an integer greater than 0 and less than 100

Due to its close relationship with throughput, the Parallel scavenge collector is often called a "throughput-first" collector.

Serial Old Collector

The Serial Old collector is the old generation version of the Serial collector. It is also a single-threaded collector and uses the "mark-sort" algorithm;

The main significance of this collector is also to be used by virtual machines in Client mode;

If it is in Server mode, then it has two main uses:

  1. One use is in JDK1.5 and previous versions, as an old generation used with the Parallel scavenge collector;
  2. Another use is as a backup plan for the CMS collector, used when Concurrent Mode Failure occurs in concurrent collection.

The working mode of the Serial Old collector is shown in the figure below (used with Serila):

Insert image description here

Parallel Old Collector

Parallel Old is the old generation version of the Parallel scavenge collector, using multi-threading and the "mark-collation" algorithm;

This collector was only provided in JDK1.6. Before that, the Parallel scavenge collector of the new generation could only be used with the Serial Old collector in the old generation. However, due to the single-threaded old generation collection of Serial Old, it could not be fully utilized. The advantages of multi-core CPUs may be a drag;

Until the emergence of Parallel Old, the "throughput-first" collector finally had a more veritable collector combination. In situations where throughput is important and CPU resources are sensitive, the Parallel scavenge/Parallel Old combination can be given priority;

The operation diagram of the Parallel scavenge/Parallel Old collector is as follows:

Insert image description here

Cms collector

CMS (Concurrent Mark Sweep) collector is a collector that aims to obtain the shortest recycling pause time ;

Currently, a large number of Java applications pay great attention to the response speed of the server to provide a better experience; the CMS collector is very suitable for the needs of such applications;

As can be seen from the name, CMS is implemented using the "mark-clear" algorithm. The entire process is mainly divided into four steps:

  1. Initial mark (CMS initial mark)
  2. Concurrent mark (CMS concurrent mark)
  3. Remark (CMS remark)
  4. CMS concurrent sweep

The two steps of initial marking and re-marking still require "Stop the world".

The initial mark is just an object that can be directly associated with the GC Roots under the mark, and it is very fast;

Concurrent marking is the process of GC Roots Tracing;

Remarking refers to the part of the record that changes due to the user thread continuing to run when concurrent marking is corrected; the pause time in this phase is generally slightly longer than the initial marking, but much shorter than the concurrent marking phase;

Since in the entire process, the GC thread works together with the user thread in the longest concurrent marking and concurrent clearing phases; therefore, overall, the CMS GC thread is executed concurrently with the user thread;

Through the following figure, you can clearly see the operation process of the CMS collector:

Insert image description here

The CMS collector is an excellent collector with the following advantages: concurrent collection and low pause; SUN officially calls it a "concurrent low-pause" collector;

But CMS is far from perfect. It has three main shortcomings:

  1. The CMS collector is very sensitive to CPU resources;
  2. The CMS collector cannot handle "floating garbage";
  3. CMS collection is implemented using the "mark-and-clear" algorithm, which means that after collection, a large amount of space fragments will be generated;
G1 Collector

The G1 collector is a server-side garbage collector. The mission given to it by the Hotpot virtual machine is to replace the CMS collector in JDK1.5 in the future.

Compared with other collectors, G1 has the following characteristics:

  1. Parallelism and concurrency: G1 can make full use of the advantages of multi-CPU and multi-core to shorten the Stop-the-world time; some other collectors originally need to suspend user threads to perform GC actions, but G1 can still allow users to perform GC actions during GC. The thread continues executing;
  2. Generational collection: Like other collections, the concept of generational collection is still retained in G1;
  3. Spatial integration: Generally speaking, G1 implements the collector based on the "mark-clear" algorithm, which avoids the memory fragmentation caused by the "mark-clear" algorithm used by CMS;
  4. Predictable pauses: This is a major advantage of G1 over CMS: in addition to pursuing low pauses, G1 can also establish a predictable low pause model; it allows users to clearly specify the amount of time spent within a period of M milliseconds. The time on GC does not exceed N milliseconds, which is almost already a characteristic of the real-time Java (RTSJ) garbage collector.

The collectors before G1 collected based on the new generation and the old generation, but this is no longer the case with G1.

The G1 collector divides the Java heap into multiple independent regions (Regions) of equal size. Although the concepts of the new generation and the old generation are still retained, the new generation and the old generation are no longer physically isolated. They are all part of the Region. (not necessarily consecutive) sets.

The G1 collector can establish a predictable pause time model because it can plan to avoid a full area garbage collection in the entire Java heap. G1 tracks the value of garbage accumulation in each Region (the amount of space obtained by recycling and the experience value of the time required for recycling). A priority list is maintained in the background, and the Region with the greatest value is recycled first according to the allowed collection time (this is the origin of Garbage-first).

This method of using Region to divide memory space and prioritize recycling ensures that the G1 collector can obtain the highest possible recycling efficiency within a limited time.

In the G1 collector, the virtual machine uses Remember Set to avoid full heap scans for references between Regions, or object references between the new generation and the old generation in other collectors;

Each Region in G1 has a corresponding Remember Set. When the program writes Reference type data, the virtual machine first generates a write barrier to temporarily interrupt the writing operation and checks whether the object pointed to by Reference belongs to a different Region (during generational collection, It is to check whether the object in the old generation refers to the new generation object), if so, record the reference information through CardTable into the Remember Set of the Region to which the referenced object belongs; when garbage collection is performed, in the enumeration range of the GC Root By adding a Remember Set, you can ensure that the entire heap will not be scanned and there will be no omissions.

If the operation of maintaining the Remember Set is not counted, the operation of the G1 collector can be roughly divided into the following operations:

  1. initial mark
  2. concurrent marking
  3. final mark
  4. Screening and recycling

The operation diagram of the G1 collector is roughly as follows:

Insert image description here

Understanding GC logs
0.144: [GC (System.gc()) [PSYoungGen: 9359K->696K(153088K)] 9359K->704K(502784K), 0.0180797 secs] [Times: user=0.00 sys=0.00, real=0.02 secs] 
0.162: [Full GC (System.gc()) [PSYoungGen: 696K->0K(153088K)] [ParOldGen: 8K->616K(349696K)] 704K->616K(502784K), [Metaspace: 3201K->3201K(1056768K)], 0.0034062 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
Heap
 PSYoungGen      total 153088K, used 1316K [0x0000000715f00000, 0x0000000720980000, 0x00000007c0000000)
  eden space 131584K, 1% used [0x0000000715f00000,0x00000007160490d0,0x000000071df80000)
  from space 21504K, 0% used [0x000000071df80000,0x000000071df80000,0x000000071f480000)
  to   space 21504K, 0% used [0x000000071f480000,0x000000071f480000,0x0000000720980000)
 ParOldGen       total 349696K, used 616K [0x00000005c1c00000, 0x00000005d7180000, 0x0000000715f00000)
  object space 349696K, 0% used [0x00000005c1c00000,0x00000005c1c9a328,0x00000005d7180000)
 Metaspace       used 3208K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 348K, capacity 388K, committed 512K, reserved 1048576K

The log format of each collector is determined by their own implementation; in other words, the log format of each collector can be different;

As can be seen from the above log:

  1. 0.144 and 0.162 respectively represent the time when GC occurs: the meaning of this number is the number of seconds that have passed since the virtual machine was started.
  2. [GC and [Full GC, indicate the pause type of this garbage collection, rather than distinguishing between new generation GC and old generation GC ; indicating that this GC is Stop-the-world.
  3. [GC (System.gc()): If the collection is triggered by calling System.gc(), then it is displayed like this;
  4. [PSYoungGen: Indicates the Parallege Scavenge collector used, and the collection area is the new generation;
  5. 9359K->696K(153088K): The memory change inside the square brackets indicates the used capacity of the memory area before GC -> the used capacity of the memory area after GC
  6. 9359K->704K (502784K): Memory changes outside the brackets, indicating the used capacity of the Java heap before GC -> the used capacity of the Java heap after GC
  7. [Times: user=0.00 sys=0.00, real=0.02 secs]: The meaning here is consistent with the Linux Time command output, which respectively indicates the CPU time consumed in user mode, the CPU time consumed in kernel mode, and the time experienced from the beginning to the end of the operation. Wall clock time; (The difference between CPU time and wall clock time: wall clock time includes various non-operational waiting times, such as waiting for disk IO, waiting for thread blocking, etc.; while CPU time does not include these times)
Summary of garbage collector parameters

Below are some common parameters related to virtual machine garbage collection:

  1. UseSerialGC: The default value when the virtual machine runs in Client mode; turn this switch on and the Serial/Serial Old combination will be used for GC.
  2. UseParNewGC: After opening, the ParNew/Serial Old combination will be used for GC.
  3. UseConcMarkSweapGC: After opening, the ParNew+CMS+Serial Old combination will be used for GC.
  4. UseParallelCG: After opening, use Parallege Scavenge+Serial Old combination for GC
  5. SurvivorRatio: The capacity ratio of the Eden area and the Survivor area in the new generation, the default is 8
  6. PretenureSizeThreshOld: directly promoted to the size of the old generation
  7. MaxTenuringThreshOld: The age of the object directly promoted to the old generation
  8. UseAdaptiveSizePolicy: Dynamically adjust the size of Java areas and the age of entering the old generation
  9. ParallelGCThreads: Set the number of threads for memory recycling during parallel GC
  10. CMSInitiatingQccupancyFraction: Set how much the CMS collector is occupied in the old generation before triggering the GC; the default is 68%; only valid for the CMS collector
  11. UseCMSCompactAtFullCollection: Set whether CMS will perform memory defragmentation after GC.
  12. CMSFullGCBeforeFraction: Set the CMS to perform several GCs and then perform memory defragmentation.

Memory allocation and recycling strategies

The automatic memory management of the Java system can ultimately be summed up and automatically processed into two problems: allocating memory to objects and recycling the memory allocated to objects;

Generally speaking, the memory allocation of objects is allocated on the heap. The objects are mainly allocated in the Eden area of ​​the new generation. If the local thread allocation buffer is started, it will be allocated on the TLAB according to thread priority; in a few cases, it can also be allocated on the heap. Directly allocated in the old generation, the specific allocation details depend on the type of garbage collector currently used, and are also related to the configuration parameters of the virtual machine.

Next, we will explain several common memory allocation rules and verify these rules through code.

  1. Objects are distributed first in Eden

    In most cases, objects will be allocated in the Eden area of ​​the new generation. When the Eden area does not have enough space for allocation, the virtual machine will initiate a Minor GC;

    What is the difference between Minor GC and Full GC?

    1. Cenozoic GC (Minor GC): refers to the GC that occurs in the new generation; because most Java objects have the characteristics of being born and destroyed, Minor GC is very frequent and the recycling speed is also very fast.
    2. Old generation GC (Major GC/Full GC): refers to the GC that occurs in the old generation; when Major GC appears, it is usually accompanied by at least one Minor GC (not absolutely, in the Parallege Scavenge collector collection strategy, there is a direct Major GC strategy). The speed of Major GC is generally more than 10 times slower than Minor GC.
  2. Large objects enter the old generation directly

    ​ The so-called large objects refer to Java objects that require a large amount of continuous memory, typically very long strings and arrays; large objects often appear, which can easily cause the GC to be triggered in advance to meet the demand when there is still a lot of space in the memory. Large contiguous space to "place" this object

  3. Long-lived objects will enter the old generation

    The virtual machine defines an object age counter for each object. If the object is born in Eden and still survives after experiencing a Minor GC, and can be accommodated by the Survivor, it will be moved to the Survivor area and the age will be set to 1; the object Every time a "Minor GC" survives in the Survivor area, the object's age increases by 1 year; when its age increases to a certain level (default 15 years old), it will be promoted to the old generation;

    As for the age threshold for promotion to the old generation, it can be configured through the parameter -XX:MaxTenuringThreshOld

  4. Object dynamic age determination

    In order to adapt to the memory conditions of different programs, the virtual machine does not always require that the object age must reach a threshold before it can be promoted to the old generation; if the size of all objects of the same age in the Survivor exceeds the Survivor memory space, then objects that are greater than or equal to this age will be Promote to the old generation; no need to wait until the threshold age of XX:MaxTenuringThreshOld is met

  5. Space allocation guarantee

Performance monitoring and troubleshooting

JDK command line tools

SUN JDK monitoring and troubleshooting tools

  1. jps: JVM Process Status Tool, displays all Hotspot virtual machine threads in the system
  2. jstat: JVM Statistics Monitoring Tool, used to collect various aspects of virtual machine operating data
  3. jinfo: Configuration Info for java, displays virtual machine configuration information
  4. jmap: Memory Map for Java: Generate memory dump snapshot of virtual machine
  5. jhat: JVM Heap Dump Browser: used to analyze Heap Dump files, it will create an Http/Html server, allowing users to view the analysis results on the browser
  6. jstack: Stack Trace for Java, showing virtual machine thread snapshots
jps: Virtual machine process status tool

JVM Process Status Tool, its function is similar to the UNIX ps command:

​ Can list the running virtual machine processes and display the name of the virtual machine execution main class (Main Class, the class where the main function is located), as well as the local virtual machine unique ID (Lcoal Virtual Machine Identifier, LVMID) of these processes.

Although the function is relatively simple, he does use the JDK command line tool most frequently, because most other tools rely on the LVMID it queries to determine which virtual machine process to monitor ;

Command format:

jps [option] [hostid]

Execution example:

C:\Users\lixuewen>jps -l
12912 -- process information unavailable
13744 com.twsz.mom.oauth.OauthApplication
16128 org.jetbrains.jps.cmdline.Launcher
17216 com.twsz.mom.mm.MaterialApplication
19620 org.apache.catalina.startup.Bootstrap
21236 sun.tools.jps.Jps
10744 com.twsz.mom.system.SystemApplication
12344 com.twsz.mom.gateway.GatewayApplication
14280
11500 com.twsz.mom.prod.ProductionApplication
15196 org.jetbrains.jps.cmdline.Launcher

jps can query the process status of the remote virtual machine with the RMI service enabled through the RMI protocol. The hostid is the remote host IP registered in the RMI registry.

Main options of jps command:

  1. -q: Output only LVMID, omit the main class name
  2. -m: Output only the functions passed to the main class main() function when the virtual machine starts
  3. -l: Output the full name of the main class. If the process executes a Jar package, output the Jar path.
  4. -v: Output the virtual machine parameters when the virtual machine process starts
jstat: virtual machine statistics monitoring tool

JVM Statistics Monitoring Tool, a tool for users to monitor various running status information of virtual machines

It can display the class loading, memory, garbage collection, JIT compilation and other operating data in the local or remote virtual machine process. There is no GUI graphical interface and only plain text information is provided;

Command format:

jstat [option vmid [interval [s|ms] ] [count] ]

Format description:

  1. If it is a local virtual machine, the vmid and LVMID are consistent; if it is a remote virtual machine, the format of vmid should be:

    ​ [protocol:] [//] lvmid [ @hostname [: port] /servername ]

  2. interval and count represent the interval and the number of queries. If defaulted, it means that the query is only performed once;

  3. Assume that the garbage collection status of process 10744 is queried every 250 milliseconds for a total of 20 times. The command is:

    ​ jstat -gc 10744 250 20

  4. option indicates the virtual machine information to be queried, which is mainly divided into three categories: class loading, garbage collection, and runtime compilation status.

    1. -class: Monitor class loading, unloading quantity, total space and loading time
    2. -gc: Monitor garbage collection, Java heap, etc.
      1. -gccapacity: mainly focuses on the maximum and minimum space used in each area of ​​the Java heap
      2. -gcutil: mainly focuses on the percentage of used space in total space
      3. -gccause: Similar to the previous one, but the reason for triggering the last GC will be output.
      4. -gcnew: Monitor the new generation GC status
      5. -gcold: Monitor the GC status of the old generation
      6. -gcoldcapacity: Mainly focused on the maximum and minimum space used in the old generation
      7. -gcpermcapacity: mainly focuses on the maximum and minimum space used by the persistent generation
    3. -compiler: Output JIT compiled methods, time-consuming and other information
    4. -printcompilation: Output methods that have been JIT compiled

Execution example:

C:\Users\lixuewen>jstat -gcutil 11500
  S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT
  0.00  95.10   5.35  40.95  94.34  91.10     45    1.481     5    1.436    2.917

It can be seen from the execution results:

​ The new generation Eden area (E) uses 5.35% of the space, the two Survivor areas (S0, S1) occupy 0% and 95.10% of their respective areas, and the old generation (O) and permanent generation (M) respectively Use 40.95% and 94.34% of the space;

Since the program was run, Minor GC (YGC) occurred 45 times, with a total time of 1.481 seconds, Full GC (FGC) 5 times, with a total time of 1.436 seconds, and the total time of all GCs (GCT) was 2.917 seconds.

jstat provides a plain text display of virtual machine running information, and the following tool Virvul VM provides a visual display page, which may be more intuitive.

jinfo:Java configuration information tool

Configration Info for java, you can view and adjust various parameters of the virtual machine in real time;

Use the jps -v command to view the list of specified parameters displayed when the virtual machine is started; if you want to know the default values ​​of parameters that are not displayed specified, you can use jinfo -flag to query.

jinfo -sysprops can print out the contents of System.getProperties() of the virtual machine process;

After JDK1.6, the ability to modify virtual machine parameters during runtime has been added. You can use -flag [+|-] name or -flag name=value to modify some of the virtual machine parameters that are writable during runtime .

jinfo command format:

jinfo [option] pid

Execution example:

C:\Users\lixuewen>jinfo -sysprops
Usage:
    jinfo [option] <pid>
        (to connect to running process)
    jinfo [option] <executable <core>
        (to connect to a core file)
    jinfo [option] [server_id@]<remote server IP or hostname>
        (to connect to remote debug server)

where <option> is one of:
    -flag <name>         to print the value of the named VM flag
    -flag [+|-]<name>    to enable or disable the named VM flag
    -flag <name>=<value> to set the named VM flag to the given value
    -flags               to print VM flags
    -sysprops            to print Java system properties
    <no option>          to print both of the above
    -h | -help           to print this help message

C:\Users\lixuewen>jinfo -flag MetaspaceSize 11500
-XX:MetaspaceSize=21807104
jmap: Java memory mapping tool

Memory Map for Java, used to generate heap dump snapshots (commonly known as heapdump or dump files); you can also use the above

-XX:+HeapDumpOnOutofMemoryError configuration parameter, automatically generates a dunp file when OOM occurs;

The jmap command is not just for getting dump files, it can also query finalize execution queue, Java heap and permanent generation details such as space usage and

Which collector to use etc.

Command format:

jmap [option] vmid

The legal values ​​and meanings of option are as follows:

  1. -dump: Generate Java heap dump snapshot; the format is: jmap -dump:live,format=b,file=heap.bin
  2. -finalizerinfo: Displays the object information waiting for the Finalizer thread to execute the finalise method in F-QUEUE
  3. -heap: Display Java heap details; only valid under Linux/Solaris
  4. -histo: Display object statistics in the heap
  5. -permstat: Use ClassLoader as the statistical caliber to display the permanent generation memory status
  6. -F: When the virtual machine process does not respond to the -dump command, you can use this command to force a dump snapshot; only valid under Linux/Solaris

Execution example:

C:\Users\snow>jmap -dump:live,format=b,file=heap.bin 11500
Dumping heap to C:\Users\snow\heap.bin ...
Heap dump file created
jhat: Virtual machine heap storage snapshot analysis tool

JVM Heap Dump Browser, used in conjunction with jmap, is used to analyze the heap dump snapshot generated by jmap;

jhat has a built-in HTTP/HTML micro-server. After the analysis results of the dump file are generated, they can be viewed with a browser;

In actual use, jhat is generally not used directly to analyze dump files. There are two main reasons:

  1. Dump analysis is generally not performed on the application server because analysis is a time-consuming and hardware-resource-consuming process. Try to analyze the dump file on other machines. Since analysis is done on other machines, there is no need to be subject to command line tool restrictions. Got it
  2. The analysis function of jhat is relatively simple. Later, we will introduce Virtual VM and other professional analysis tools to achieve more powerful and professional analysis functions.

Execution example:

C:\Users\lixuewen>jhat heap.bin
Reading from heap.bin...
Dump file created Wed Dec 21 22:24:20 CST 2022
Snapshot read, resolving...
Resolving 9370112 objects...
Chasing references, expect 1874 dots..............................................................................................................................
Eliminating duplicate references..........................................................................................................................................................................................................................
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.

After "Server is ready" appears on the screen, enter "http://localhost:7000/" in the browser to see the analysis results:

Insert image description here

jstack: Java stack tracing tool

Stack Trace for Java is used to generate a thread snapshot of the virtual machine at the current moment (generally called a threaddump file or javacore file);

A thread snapshot is a stack collection of methods being executed by each thread of the virtual machine at the current moment. The main purpose of generating a thread snapshot is to locate the cause of long pauses in threads , such as deadlocks between threads, infinite loops, or long periods of time when requesting external interfaces. Waiting is a common reason;

Command format:

jstack [option] vmid

The legal values ​​and meanings of option are as follows:

  1. -F: Force output stack when normal output request is not responded to
  2. -l: In addition to outputting the stack, display attachment information about the lock
  3. -m: If a native method is called, the C/C++ stack can be displayed

Execution example:

C:\Users\snow>jstack -l 11500
2022-12-22 10:39:35
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.201-b09 mixed mode):

"Keep-Alive-Timer" #957 daemon prio=8 os_prio=1 tid=0x000000002f9d7800 nid=0x4f88 waiting on condition [0x000000007a37f000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
        at java.lang.Thread.sleep(Native Method)
        at sun.net.www.http.KeepAliveCache.run(KeepAliveCache.java:172)
        at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
        - None

"logback-2" #802 daemon prio=5 os_prio=0 tid=0x000000002f9e2800 nid=0x22b8 waiting on condition [0x000000006a67f000]
   java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00000005d8c9c218> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1081)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
        at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
        - None

"com.alibaba.nacos.client.Worker.longPolling.fixed-10.38.102.16_8848-dev" #625 daemon prio=5 os_prio=0 tid=0x000000002f9d6000 nid=0x3d88 runnable [0x0000000057f1d000]
   java.lang.Thread.State: RUNNABLE
        at java.net.SocketInputStream.socketRead0(Native Method)
        at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
        at java.net.SocketInputStream.read(SocketInputStream.java:171)
        at java.net.SocketInputStream.read(SocketInputStream.java:141)
        at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
        at java.io.BufferedInputStream.read1(BufferedInputStream.java:286)
        at java.io.BufferedInputStream.read(BufferedInputStream.java:345)
        - locked <0x0000000736e4c250> (a java.io.BufferedInputStream)
        at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:735)
        at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:678)
        at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1587)
        - locked <0x0000000736e431a0> (a sun.net.www.protocol.http.HttpURLConnection)
        at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1492)

In JDK1.5, the Thread class added a getAllStrackTraces() method to obtain the StackTraceElement objects of all threads in the virtual machine; using this method, most of the functions of jatack can be realized with a few simple lines of code; in practice, it can be considered Create an administrator page and view Java stack information through the browser at any time

hsdis:jit generates code disassembly

HSDIS is a disassembly plug-in for Hotpot virtual machine JIT compiled code officially provided by SUN; simply speaking, it is a decompilation tool;

JDK visualization tool

Jconsole is a virtual machine monitoring tool that has been provided since the JDK1.5 era; VisualVM was released in JDK1.6 Update 7 and is an all-in-one troubleshooting tool promoted by SUN;

jconsole:Java monitoring and management console

Jconsole is a JMX-based visual monitoring and management tool;

  1. Start jconsole

    ​ After starting jconsole through "jconsole.exe" in the JDK/bin directory, all virtual machine processes running on the local machine will be automatically searched, and the user does not need to use jps to query, as shown in the figure below;

Insert image description here

Double-click to select a process to start monitoring; you can also use the "Remote Process" below to connect to the remote server and monitor the remote virtual machine process.

Insert image description here

After double-clicking a specific thread, you enter the jconsole main interface, which includes overview, memory, threads, classes, VM summary, and MBeans;

"Overview" displays an overview of the main operating data of the entire virtual machine, including curve graphs of four types of information: "Heap memory usage", "Threads", "Classes", and "CPU usage". These graphs are the memory, Summary of thread and class tab information;

  1. Memory monitoring

    The "Memory" tab is equivalent to the visual jstat command, used to monitor the changing trend of memory managed by the virtual machine (Java heap and permanent generation);

Insert image description here

  1. Thread monitoring

    The "Thread" tab is equivalent to the visual jstack command. When a thread is paused, you can use this tab for monitoring and analysis;

Insert image description here

visualvm: all-in-one visual troubleshooting tool

VisualVM is by far the most powerful runtime monitoring and troubleshooting tool released with the JDK;

The official description of VisualVM is "All in one", indicating that in addition to running monitoring and fault handling, it also provides many other functions, such as performance analysis, etc.;

Another great advantage of VisualVM is that it does not require the monitored program to run based on a special Agent, so it has little impact on the actual performance of the application, allowing it to be directly used in production environments.

  1. VisualVM compatibility range and plug-in installation

    ​ VisualVM is developed based on the NetBeans platform, so it has plug-in extension features from the beginning. Through plug-in extension support, VisualVM can do:

    1. Display virtual machine processes and process configuration and environment information (jps, jinfo)

    2. Monitor the application's CPU, GC, heap, method area and thread information (jstat, jstack)

    3. dump and analyze heap dump snapshots (jmap, jhat)

    4. Method-level program running performance analysis to find out the methods that are called the most and take the longest to run.

    5. Offline program snapshot: Collect the runtime configuration, thread dump, memory dump and other information of the program to create a snapshot. BUGs can be sent to developers for BUG feedback.

    6. Wireless possibilities provided by other plugins

    ​ Plug-ins can be installed manually. After downloading the *.nbm package on the relevant website, click "Tools" -> "Plug-ins" -> "Downloaded", and specify the nbm package path in the window that opens to install it;

    ​ However, manual installation is not common. Use the automatic installation function of VisualVM to find most of the plug-ins you need. In a network environment, click "Tools" -> "Plug-ins" -> "Available Plug-ins". In the pop-up plug-in list, you can install it as needed:

Insert image description here

After installing the plug-in, select a program that needs to be monitored in the application on the left to enter the main page of the program:

Insert image description here

The tab overview, monitoring, threads, GC, etc. on the right side of VisualVM are similar to the Jconsole introduction above and can be experienced by yourself;

  1. Generate and browse heap dump snapshots

    There are two ways to generate a dump heap snapshot in VisualVM.

    1. In the Applications window, right-click the specified program and select Heap Dump

    2. In the "Applications" window, double-click the specified program, select the "Monitor" tab on the program's main page, and click "Dump"

    After the dump file is generated, in the "Application" window, a [heapdump] subnode will be added under the program, and the dump file will be opened in the main interface on the right;

Insert image description here

If you want to send or save the dump file, click on this node to select Save As, otherwise the dump file will be lost when VisualVM is closed;

To open an external dump file that already exists, select the "Load" function on the file menu to import the external dump file;

  1. Analyze program performance

    In the Profiler tab, VisualVM provides method-level CPU analysis and memory analysis during program running; profiling analysis will definitely have a greater impact on program performance, so this function is generally not used in production environments ;

    To start analysis, first select one of the "CPU" and "Memory" buttons, then switch to the application window and select a specific program. VisualVM will record the methods called by the CPU during this period:

    1. If it is CPU analysis, the number of executions of each method and the execution time will be counted.
    2. If it is memory analysis, the number of objects associated with each method and the memory space occupied by these objects will be counted.
    3. After the analysis is completed, click "Stop" to end monitoring.
  2. BTrace dynamic log tracking

    BTrace is an "interesting" VisualVM plug-in that can also run independently;

    The function is to dynamically add debugging code that does not exist through Hotspot virtual machine Hotswap technology without stopping the running of the target program ;

    This function is very meaningful for actual production applications: when encountering a program problem, you need to check the execution result information of key codes, but if there is no log added during development, you have to stop the service and add the log. to troubleshoot the problem; it will be very annoying when the production environment cannot be stopped at will, resulting in troubleshooting.

    After installing the BTrace plug-in, in the application window, right-click the specified program and select "Trace Application..." to enter the BTrace panel;

    There are many other uses of BTrace. Printing call stacks, parameters, and method return values ​​is just a basic application. There are many examples on its website for performance monitoring, locating connection leaks, memory leaks, and solving multi-thread competition issues. Those who are interested can check its related websites;

    BTrace parameter link: https://www.jianshu.com/p/93e94b724476
    Click the specified program, select the "Monitor" tab on the program's main page, and click "Heap Dump"

    After the dump file is generated, in the "Application" window, a [heapdump] subnode will be added under the program, and the dump file will be opened in the main interface on the right;

    [External link pictures are being transferred...(img-KdwF4SnW-1678267817768)]

    If you want to send or save the dump file, click on this node to select Save As, otherwise the dump file will be lost when VisualVM is closed;

    To open an external dump file that already exists, select the "Load" function on the file menu to import the external dump file;

  3. Analyze program performance

    In the Profiler tab, VisualVM provides method-level CPU analysis and memory analysis during program running; profiling analysis will definitely have a greater impact on program performance, so this function is generally not used in production environments ;

    To start analysis, first select one of the "CPU" and "Memory" buttons, then switch to the application window and select a specific program. VisualVM will record the methods called by the CPU during this period:

    1. If it is CPU analysis, the number of executions of each method and the execution time will be counted.
    2. If it is memory analysis, the number of objects associated with each method and the memory space occupied by these objects will be counted.
    3. After the analysis is completed, click "Stop" to end monitoring.
  4. BTrace dynamic log tracking

    BTrace is an "interesting" VisualVM plug-in that can also run independently;

    The function is to dynamically add debugging code that does not exist through Hotspot virtual machine Hotswap technology without stopping the running of the target program ;

    This function is very meaningful for actual production applications: when encountering a program problem, you need to check the execution result information of key codes, but if there is no log added during development, you have to stop the service and add the log. to troubleshoot the problem; it will be very annoying when the production environment cannot be stopped at will, resulting in troubleshooting.

    After installing the BTrace plug-in, in the application window, right-click the specified program and select "Trace Application..." to enter the BTrace panel;

    There are many other uses of BTrace. Printing call stacks, parameters, and method return values ​​is just a basic application. There are many examples on its website for performance monitoring, locating connection leaks, memory leaks, and solving multi-thread competition issues. Those who are interested can check its related websites;

    BTrace uses parameter link: https://www.jianshu.com/p/93e94b724476

Guess you like

Origin blog.csdn.net/weixin_40709965/article/details/129407977