JVM Monitoring and Diagnostics Tools (GUI)

jconsole

  • Starting with Java5, built-in Java monitoring and administration console in the JDK.
  • JMX is a GUI performance monitoring tool based on Java Management Extensions (JMX) for monitoring memory, threads, and classes in the JVM.
  • The official tutorial
  1. Start the
  • In JDK /bin, start the jconsole.exe command
  • Enter jConsole in CMD
  1. Three connection modes
  • Local
    • JConsole is used to connect to a JVM running on the local system, and the program is being executed by the same user who needs to run JConsole. JConsole uses the authorization of the file system to connect to the platform’s MBean server through the RMl connector. This ability to monitor from a local connection is only available in Sun’s JDK.
  • Remote
    • Use the following URL through the RMI connector is connected to a JMX agent, service: JMX. RMI: / / / jndi/RMI: / / hostNane: portNum/jmxrmi. For JConsole to establish a connection, you need to set mx.remote.credentials in the environment variable to specify the user name and password for authorization.
  • Advanced
    • Use a special URL to connect to the JMX agent. It is common to use your own custom connectors to connect to JMX agents instead of those provided by RMI, or an application that implements JMX and JMX Rmote using JDK1.4.

Visual VM

  • Visual VM is a powerful all-in-one Visual tool for fault diagnosis and performance monitoring.
  • It integrates a number of DK command line tools, using Visual VM can be used to display virtual machine process and process configuration and environment information (JPS, JINFO), monitor the application of CPU, GC, heap, method area and thread information (Jstat, JStack), and even replace JConsole.
  • After DK 6 Update 7, VisualVM was released as part of the JDK (VisualVM in the JDK/bin directory), i.e., it’s completely free.
  • In addition, Visual VM can be installed as standalone software

One of the features of Visual VM is that it supports plug-in extensions and is very easy to install. We can either download the plug-in file *.nbm offline, and then add the downloaded plug-in under the downloaded page of the Plugin dialog box. You can also install plug-ins online on the available plug-ins page. (Here it is recommended to install :VisualGC) plug-in address

  • Local connection
    • Monitors CPU, classes, threads, and so on for native Java processes
  • The remote connection
  1. Determine the IP address of the remote server
  2. Add JMX (using JMX technology to specifically monitor which Java process on the remote server
  3. Modify the bin/catalina.sh file to connect to remote Tomcat
  4. In the… Add the jmxremote.access and jmxremote.password files to /conf
  5. Change the server IP address to a public IP address
  6. Set ali Cloud security policies and firewall policies
  7. Start Tomcat, view tomcat startup logs and port listening. 8 Enter the port number, user name, and password in JMX
  • The main function
  1. Generate/read heap memory snapshot

  1. View JVM parameters and system properties

  1. View running VM processes
  2. Generate/read thread snapshot

  1. Real-time monitoring of program resources

  1. Other features
    • JMX proxy connection
    • Remote environment monitoring
    • CPU analysis and memory analysis

MAT

The MAT(Memory Analyzer Tool) is a powerful Java heap Memory Analyzer. It can be used to find memory leaks and to view memory consumption.

MAT is developed based on Eclipse and can be used not only on its own, but also embedded in Eclipse as a plug-in. Is a free performance analysis tool, very easy to use. Download the MAT

Hprof file information:

  • All object information, including object instances, member variables, primitive type values stored in the stack, and references to other objects stored in the heap.
  • All class information, including classLoaders, class names, parent classes, static variables, and so on. GCRoot reference paths to all of these objects
  • Thread information, including the thread’s call stack and thread-local variables for that thread (TLS)

Disadvantages:

MAT is not a one-size-fits-all tool, and it can’t handle all types of heap-stored files. However, mainstream manufacturers and formats, such as THE HPROF binary heap storage files adopted by Sun, HP, SAP, and IBM PHD heap storage files can be well parsed.

Description:

Most appealing is the ability to quickly generate memory leak reports for developers, making it easy to locate and analyze problems. Although MAT has such powerful functions, memory analysis is not so simple as to be completed with one click. Many memory problems still need to be found through experience and intuition based on the information MAT presents to us.

Main common functions:

  1. histogram

Shows the number of instances of each class and the sum of their heap or Retainedheap

  1. thread overview

View the Java thread in the system and view information about local variables

  1. Get the relationship between objects that refer to each other

  • With outgoing References: Tree of references to other objects for which the current object is the root
  • With Incoming References: Tree of which objects the current object is referenced by
  1. Shallow and deep

Shallow pile (Shallow Heap)

Is the amount of memory consumed by an object. In a 32-bit system, an object reference would take up 4 bytes, an int would take up 4 bytes, a long would take up 8 bytes, and each object header would take up 8 bytes. Depending on the heap snapshot format, the size of the object may be aligned toward 8 bytes.

Take String as an example: 2 int values take up 8 bytes, object reference takes up 4 bytes, object header 8 bytes, total 20 bytes, aligned to 8 bytes, so it takes up 24 bytes. () in the jdk7

These 24 bytes are the shallow heap size of a String. It is independent of the actual value of the String. Regardless of the String length, the shallow heap size is always 24 bytes.

Calculate object size

Retained Set:

The reserved set of object A refers to the collection of all objects (including object A itself) that can be released after object A is garbage collected. That is, the reserved set of object A can be regarded as the collection of all objects that can only be accessed directly or indirectly through object A. In layman’s terms, it refers to the collection of objects held only by object A.

Deep (Retained Heap Heap) :

The deep heap is the sum of the shallow heap sizes of all objects in the reserved set of objects.

Note: The shallow heap refers to the memory occupied by the object itself, not the size of its internal reference objects. The deep heap of an object is the sum of the shallow heaps of all objects that can only be accessed (directly or indirectly) by the object, i.e. the real space that can be freed after the object is reclaimed.

The actual size of the object

Another commonly used concept is the actual size of an object. Here, the actual size of an object is defined as the sum of the shallow heap sizes of all objects that can be touched by an object, which is commonly referred to as the object size. Compared to deep heap, this may seem more intuitive and accepted in everyday development, but in reality, this concept has nothing to do with garbage collection.

The following figure shows A simple object reference diagram, with object A referring to C and D and object B referring to C and E. So the shallow heap size of object A is only A, excluding C and D, and the actual size of object A is the sum of A, C, and D. The size of A’s deep heap is the sum of A and D. Because object C can be accessed through object B, it is not in the range of object A’s deep heap.

Case study: StudentTrace

  1. Dominant tree

The concept of Dominator Tree comes from graph theory.

MAT provides a graph of objects called the Dominator Tree. The dominance tree represents the dominance relationship between object instances. In an object reference graph, all paths to object B pass through object A, and object A is considered to dominate object B. Object A is considered to be the direct dominator of object B if object A is the nearest dominant object to object B. The dominance tree is based on the reference graph between objects. It has the following basic properties:

  • The subtree of object A (the set of all objects governed by object A) represents the retained set of object A, that is, the deep heap.
  • If object A governs object B, then the direct dominator of object A also governs object B.
  • The edges of the ruling tree do not correspond directly to the edges of the object reference graph.

The image below shows the object reference graph on the left and the dominance tree corresponding to the image on the right. Objects A and B are directly dominated by the root object, and since the path to object C can go through either A or B, the direct dominator of object C is also the root object. Object F and object D refer to each other, because all paths to object F must pass through object D, so object D is the direct dominator of object F. All paths to object D must go through object C, and even the reference from object F to object D, starting from the root node, also goes through object C. Therefore, object C is the direct dominator of object D.

Similarly, object E governs object G. Object H can be reached through object D or object E, so neither object D nor E can dominate object H. However, object C can reach either D or E through object C, so object C is the direct dominator of object H.

In MAT, click the Object Domination tree button on the toolbar to open the object domination tree view.

JProfiler

When running Java, you sometimes want to test the memory footprint of the runtime, so you need to use the test tool to check. The Eclipse Memory Analyzer Too1 (MAT) plug-in is available in Eclipse for testing, and there is also a plugin for IDEA, JProfiler.

JProfiler is a Java application performance diagnostic tool developed by EJ-Technologies. Powerful, but charged.

Official website download address

Idea install VisualVM, Jprofiler, jclasslib

JProfier data collection modes are divided into two types :Sampling and Instrumentation.

  • Instrumentation: This is JProfiler full-featured mode. Before the class is loaded, JProfier writes the relevant functionality code into the bytecode of the class to be analyzed, affecting the running JVM.
    • Advantages: Powerful. In this setting, the call stack information is accurate.
    • Disadvantages: If there are a large number of classes to be analyzed, the application performance is greatly affected and the CPU overhead may be high (depending on the Filter system). Therefore, this pattern is typically used in conjunction with filters to analyze only specific classes or packages.
  • Sampling: Similar to sample statistics, the information in method stack in each thread stack is counted every certain time (5ms).
    • Advantages: Very low CPU overhead, minimal application impact (even if you don’t configure any filters)
    • Disadvantages: Some data/features are not available (e.g., number of method calls, execution time)

Note: JProfiler itself does not specify the type of collection for the data; the collection type here is for method calls. Because most of the core functionality of JProfiler relies on data collected by method calls, it is straightforward to think of this as JProfiler’s data collection type.

/ * * *@Description: Memory leak *@Author: jianweil
 * @date: 2021/9/9 it * /
public class MemoryLeak {
    public static void main(String[] args) {

        while (true) {
            ArrayList beanList = new ArrayList();// Each loop is recycled
            for (int i = 0; i < 500; i++) {
                Bean data = new Bean();
                data.list.add(new byte[1024 * 10]);// 10KB is not collected
                beanList.add(data);
            }
            try {
                TimeUnit.MILLISECONDS.sleep(500);
            } catch(InterruptedException e) { e.printStackTrace(); }}}}class Bean {
    int size = 10;
    String info = "hello";
     //ArrayList list = new ArrayList();
    static ArrayList list = new ArrayList();
}
Copy the code
  1. OOM Example View

  1. Deadlock example view
/ * * *@Description: deadlock jstack *@Author: jianweil
 * @date: 2021/9/6 16:07 * /
public class DealLockTest {

    public static void main(String[] args) {

            Object o1 = new Object();
            Object o2 = new Object();
            new Thread(new Runnable() {
                @Override
                public void run(a) {
                    synchronized (o1) {
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("Thread 1 is running");
                        synchronized (o2) {
                            System.out.println("Thread 2 gets O1"); }}}},Thread 1 "").start();

            new Thread(new Runnable() {
                @Override
                public void run(a) {
                    synchronized (o2) {
                        System.out.println("Thread 2 is running");
                        synchronized (o1) {
                            System.out.println("Thread 2 gets O1"); }}}},Thread 2 "").start();

        System.out.println("Main thread terminated");
        try {
            Thread.sleep(1500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(new Runnable() {
            @Override
            public void run(a) {
                Map<Thread, StackTraceElement[]> all = Thread.getAllStackTraces();// Trace all threads in the current process
                Set<Map.Entry<Thread, StackTraceElement[]>> entries = all.entrySet();
                for (Map.Entry<Thread, StackTraceElement[]> en : entries) {
                    Thread t = en.getKey();
                    StackTraceElement[] v = en.getValue();
                    System.out.println("【Thread name is :" + t.getName() + "】");
                    for (StackTraceElement s : v) {
                        System.out.println("\t"+ s.toString()); }}}},"Thread 3").start(); }}Copy the code

Arthas

Arthas is an open source Java diagnostics tool on Alibaba that developers love. Troubleshoot faults online without restart. Dynamically trace Java code; Monitor VM status in real time.

The official documentation

Arthas supports JDK 6+, Linux/Mac/Windows, command line interaction, and rich Tab auto-completion to further locate and diagnose problems.

Arthas can help you when you are stuck with a problem like the following:

  • From which JAR is this class loaded? Why are all kinds of class-related exceptions reported?
  • Why didn’t the code I changed execute? Did I not commit? Got the branch wrong?
  • If you encounter a problem, you cannot debug it online. Can you only re-publish it by logging?
  • There is a problem with a user’s data processing online, but it cannot be debugged online, and it cannot be reproduced offline!
  • Is there a global view of the health of the system?
  • Is there any way to monitor the real-time health of the JVM?

jmc

Prior to Oracle’s acquisition of Sun, Oracle’s JRockit Virtual Machine provided a virtual machine diagnostic tool called JRockitMission Control.

After Oracle acquired Sun, Oracle owned both Sun Hotspot and JRockit virtual machines. In line with Oracle’s strategy for Java, the best features of JRockit will be ported to Hotspot in the future. One significant improvement is the addition of JRockit support to Sun’s JDK.

Mission Control is a tool that has been bundled with the Oracle JDK since oracle JDK 7U40. The JFR introduced in this section has been open source since Java 11. But in previous Java versions, JFR was a CommercialFeature that needed to be enabled with the Java virtual machine parameter -xx :+UnlockCommercialFeatures

If you’re interested, check out the openJDK’s Mission Control project

Java Mission Control(JMC) is a powerful tool provided by Java. Is a suite of tools for managing, monitoring, profiling, and troubleshooting Java applications.

It includes a GUI client and a number of plug-ins for collecting Java virtual machine performance data, such as the JMX Console (which gives access to MXBeans, which is used to store data for each subsystem of the virtual machine), And the highly efficient profiling tool Java Flight Recorder (JFR) built into the virtual machine.

Another advantage of JMC is that sampling, rather than traditional code placement techniques, has a very, very small impact on application performance and can be done with JMC on (the only impact may be full GC).

Java Flight Recorder sampling analysis, to use sampling, must first add parameters:

  • -XX:+UnlockCommercialFeatures
  • -XX:+FlightRecorder

Otherwise,

Start the way

  1. Method 1: -xx :StartFlightRecording= Parameters

The first is to add the -xx :StartFlightRecording= parameter when running the target Java program.

For example, in the following command, JFR collects data after the Java VM starts for 5s (delay=5s) and lasts for 20s (duration=20s). JFR saves the collected data to a specified file (filename= myrecord.jFR)

java – XX:StartFlightRecording=delay=5s,duration=20s,filename=myrecording.jfr,settings=profile MyApp

Since JFR will continue to collect data, if left unchecked, JFR can fill up all the space on your hard drive. Therefore, it is necessary to limit the data collected in this mode.

Such as:

java -XX:StartFlightRecording=maxage=10m, maxsize=100m, name=SomeLabel MyApp

  1. Method 2: Use the JFR.* subcommand of JCMD

JCMD allows JFR to start collecting data, stop collecting data, or save the collected data with the subcommands fr. start, jfr. stop, and jfr.dump.

jcmd <PID> JFR.start settings=profile maxage=10m maxsize=150m name=SomeLabel

After the above command is run, the JFR in the target process has started collecting data. At this point, we can export the collected data by running the following command:

jcmd <PID> JFR.dump name=SomeLabel filename=myrecording.jfr

Finally, we can close the JFR in the target process with the following command:

jcmd <PID> JFR.stop name=SomeLabel

  1. The graphical interface is directly opened

  • Java Virtual Machine -> Detailed ->Object Count/Object Count after GC
  • Method call sampling interval changed from 10ms to 1ms(but not less than 1ms, otherwise it will affect performance): JavaVirtual Machine -> Profiling -> Method Profiling Sample/Method Sampling Information
  • Java Application->File Read/Filewrite/Socket Read/Socket write

OQL language

MAT supports a Query Language 0QL(Object Query Language) similar to SQL. OQL uses sqL-like syntax to search and filter objects in the heap.

  1. The SELECT clause
  • In MAT, the Select clause is formatted roughly the same as SQL and is used to specify columns to display. You can use ‘*’ in the Select clause to view the referenced instance of the resulting object (equivalent to outgoing References)
    • SELECT * FROM java.util.Vector v
  • Use the “OBJECTS” keyword to display items in the returned result set as OBJECTS.
    • SELECT objects v.elementData FROM java.util.Vector v
    • SELECT OBJECTS s.value FROM java.lang.String s
  • In the Select clause, use the “AS RETAINED SET” keyword to obtain the RETAINED SET of the obtained object.
    • SELECT AS RETAINED SET * FROM com.atguigu.mat.Student
  • The “DISTINCT” keyword is used to remove duplicate objects from the result set.
    • SELECT DISTINCT OBJECTS classof(s) FROM java.lang.String s
  1. FROM clause
  • The From clause is used to specify the scope of the query, which can specify the class name, regular expression, or object address.
    • SELECT * FROM java.lang.String s
  • The following example uses regular expressions to limit the search scope and output instances of all classes under all com. XXX packages
    • SELECT * FROM “com.xxx.. *”
  • You can also search directly using the address of the class. The advantage of using the address of a class is that you can distinguish between the same type being loaded by different classloaders.
    • select * from 0x37a0b4d
  1. The WHERE clause
  • The WHERE clause is used to specify OQL query conditions. OQL queries will return only objects that meet the criteria specified in the WHERE clause. The FORMAT of the WHERE clause is very similar to traditional SQL.
  • The following example returns a char array of length greater than 10.
    • SELECT * FROM char[] s WHERE s.@length>10
  • The following example returns all strings containing the “Java” substring, using the “LIKE” operator, which takes a regular expression.
    • SELECT * FROM java.lang.string s WHERE toString(s) LIKE “.*java.*”
  • The following example returns all strings whose value field is not null, using the “=” operator.
    • SELECT * FROM java.lang.String s where s.value ! =null
  • The Where clause supports AND AND OR operations for multiple conditions. This example returns all vectors with an array length greater than 15 and a deep heap size greater than 1000 bytes.
    • SELECT * FROM java.util.Vector v WHERE v.elementData.@length>15 AN D v.@retainedHeapSize>1000
  1. Built-in objects and methods

Properties of objects in the heap can be accessed in OQL, as well as properties of proxy objects in the heap. [<alias>.] <field>. <field>. <field>.

Alias indicates the object name.

  • Access the path property of the java.io.File object, and further access the value property of path
    • SELECT toString(f.path.value) FROM java.io.File f
  • The following example shows the content of a String object, objectid, and objectAddress.
    • SELECT s.toString(), s.@objectId, s.@objectAddress FROM java.lang.String s
  • The following example shows the length of the array inside java.util.Vector.
    • SELECT v.elementData.@length FROM java.util.Vector v
  • The following example shows all java.util.Vector objects and their subtypes
    • select * from INSTANCEOF java.util.Vector

A memory leak

Reachability analysis algorithms to determine whether an object is no longer used are essentially to determine whether an object is still referenced. In this case, there are many kinds of memory leak problems due to the different implementation of the code < causing the JVM to mistakenly believe that the object is still in reference and cannot be reclaimed, causing memory leak).

  • Strictly speaking, a memory leak is when objects are no longer used by the program, but the GC cannot reclaim them.
  • In practice, however, many times poor practices (or omissions) can lead to long life cycles and even OOM, which can be called a “memory leak” in the broad sense.

Object X references object Y. The life cycle of X is longer than that of Y. So when the life cycle of Y ends, x still refers to Y, and the garbage collection period does not collect object Y; If object X also references objects A, B, and C with short life cycles, and object A in turn references objects A, B, and C, A large number of useless objects may not be reclaimed, occupying memory resources and causing memory leaks until the memory is exhausted.

The relationship between memory leaks and memory overruns: As memory leaks increase, they eventually lead to memory overruns.

Eight cases of memory leaks in Java

  1. Static collection class

Static collection classes, such as HashMap, LinkedList, and so on. If these containers are static, their lifetime is consistent with that of a JVM program, and objects in the container cannot be released until the program ends, resulting in a memory leak. Simply put, a long-life object holds a reference to a short-life object, which cannot be reclaimed because the long-life object holds a reference to it, even though the short-life object is no longer in use.

/ * * *@Description: static collection class *@Author: jianweil
 * @date: 2021/9/7 prepare * /
public class LeakDemo {

    static List list = new ArrayList();

    public void oomTests(a) {
        Object obj = new Object();// Local variableslist.add(obj); }}Copy the code
  1. The singleton pattern

The singleton pattern causes memory leaks in a similar way to static collections. Because of the static nature of the singleton, its lifetime is as long as that of the JVM, so if a singleton holds a reference to an external object, that external object will not be recycled, causing a memory leak.

  1. The inner class holds the outer class

An inner class holds an outer class if a method on an instance object of an outer class returns an instance object of an inner class. The inner class object is referenced for a long time, and even though the outer class instance object is no longer in use, because the inner class holds the instance object of the outer class, the outer class object will not be garbage collected, which can also cause a memory leak.

  1. Various connections, such as database connections, network connections, IO connections, etc

In the process of operating the database, you need to establish a connection with the database. When the database is no longer used, you need to call the close method to release the connection with the database. Only after the connection is closed will the garbage collector reclaim the corresponding object. Otherwise, if a Connection, Statement, or ResultSet is not explicitly closed during database access, a large number of objects cannot be reclaimed, resulting in memory leaks.

public static void main( String[] args) {
    try {
        Connection conn = null;
        class.forName("com.mysql.jdbc.Driver"); conn = DriverManager.getconnection("uri".""."");
        statement stmt = conn.createstatement();
        Resultset rs = stmt.executeQuery("...");
      } catch (Exception e) {// Exception log
 
     }finally {
        //1. Close Statement
        //2. Close declared object Resultset1
        3. Close the Connection}}Copy the code
  1. Unreasonable scope of a variable

Unreasonable scope of a variable. In general, the definition of a variable is larger than the scope of its use and is likely to cause memory leaks. On the other hand, if the object is not set to NULL in a timely manner, memory leaks are likely to occur.

/ * * *@Description: static collection class *@Author: jianweil
 * @date: 2021/9/7 prepare * /
public class UsingRandom {
    private String msg; 
    public void receiveMsg(a){
        readFromNet();// Accept data from the network and save it in MSG
        saveDB();// Save MSG to the database}}Copy the code

For example, the pseudo-code above saves the received message in the variable MSG through the readFromNet method, and then calls the saveDB method to save the content of the MSG into the database. At this point, the MSG is useless, because the life cycle of THE MSG is the same as the life cycle of the object, and the MSG cannot be recycled. Hence the memory leak.

The MSG variable can actually be placed inside the receiveMsg method, and when the method is used up, the MSG life cycle ends and can be recycled. Another option is to set MSG to null after you’re done using it so that the garbage collector will reclaim the MEMORY space of the MSG.

  1. Change the hash

Change the hash value. Once an object is stored in a HashSet, the fields in the object that computed the hash value cannot be changed.

Otherwise, the modified hash of the object will be different from the hash originally stored in the HashSet. In this case, even if the Contains method retrieves the object from the HashSet using the current reference to the object as an argument, it will return the result that the object is not found, This also causes the current object to be unable to be individually removed from the HashSet collection, causing a memory leak.

That’s why strings are set to be immutable. We can safely store strings into a HashSet, or treat String as the key of a HashMap;

When we want to save our own class to a hash table, we need to make sure that the object’s hashCode is immutable.

/ * * *@Description: Change the hash value *@Author: jianweil
 * @date: 2021/9/7 prepare * /
public class LeakDemo {

    public static void main(String[] args) {
        HashSet<Point> hs = new HashSet<>();
        Point cc = new Point();
        cc.setX(10); //hashcode = 41
        hs.add(cc);
        cc.setX(20); // hashCode = 51 This behavior causes a memory leak
        System.out.println("hs.remove = " + hs.remove(cc));//false: The hashCode of the remove method has changed to 51 because of the field modification. It was 41. I can't find it
        hs.add(cc);
        System.out.println("hs.size= " + hs.size());//size = 2
        System.out.println(hs);//size = 2
    }

    static class Point {
        int x;

        public int getX(a) {
            return x;
        }

        public void setX(int x) {
            this.x = x;
        }

        @Override
        public int hashCode(a) {
            final int prime = 31;
            int result = 1;
            result = prime * result + x;
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) return true;
            if (obj == null) return false;
            if(getClass() ! = obj.getClass())return false;
            Point other = (Point) obj;
            if(x ! = other.x)return false;
            return true;
        }

        @Override
        public String toString(a) {
            return "Point{" +
                    "x=" + x +
                    '} '; }}}Copy the code
hs.remove = false
hs.size= 2
[Point{x=20}, Point{x=20}]

Copy the code
  1. Cache leakage

Another common source of memory leaks is caches, which are easy to forget once you put object references into the cache. For example, during a previous project launch, the application started very slowly until it died because the code would load a table into the cache (memory). The test environment had only a few hundred pieces of data, but the production environment had several million pieces of data.

For this problem, a WeakHashMap can be used to represent the cache. The feature of such a Map is that when there is no reference to the key other than the key itself, the Map will automatically discard the value.

/ * * *@DescriptionWeakHashMap uses comparison *@Author: jianweil
 * @date: 2021/9/7 20:50 * /
public class MapTest {


    static Map wMap = new WeakHashMap();
    static Map map = new HashMap();


    public static void init(a) {

        String ref1 = new String("obejct1");
        String ref2 = new String("obejct2");

        String ref3 = new String("obejct3");
        String ref4 = new String("obejct4");
        wMap.put(ref1, "cacheobject1");
        wMap.put(ref2, "cacheobject2");
        map.put(ref3, "cache0bject3");
        map.put(ref4, "cacheobject4");
        System.out.println("String references ref1,ref2, ref3,ref4 disappear");

    }


    private static void testweakHashMap(a) {
        System.out.println("Before iHeakHashMap CC");
        for (Object o : wMap.entrySet()) {
            System.out.println(o);
        }
        try {
            System.gc();
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("After weakHashMap G");
        for(Object o : wMap.entrySet()) { System.out.println(o); }}private static void testHashMap(a) {

        System.out.println("HashMap before Gc");
        for (Object o : map.entrySet()) {
            System.out.println(o);
        }
        try {
            System.gc();
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("After HashMap Gc");
        for(Object o : map.entrySet()) { System.out.println(o); }}public static void main(String[] args) { init(); testweakHashMap(); testHashMap(); }}Copy the code
String references ref1,ref2, Ref3,ref4 gone iHeakHashMap cc before OBEJCT2 = cacheObject2 OBEjCT1 = cacheObject1 weakHashMap G after HashMap Gc before Obejct4 = cacheObject4 OBEjct3 =cache0bject3 HashMap AFTER Gc OBEjCT4 = cacheObject4 OBEjct3 =cache0bject3Copy the code

  1. Listeners and callbacks

If a client registers a callback in the API you implement and does not show cancellation, it will accumulate.

The best way to ensure that a callback is immediately treated as garbage collection is to save only its weak references, such as saving them as keys in a weakHashMap.

Case analysis

/ * * *@Description: todo
 * @Author: jianweil
 * @date: 2021/9/7 21:01 * /
public class Stack {

    private Object[] elements;
    private int size = 0;
    private static final int DEFAULT_INITIAL_CAPACITY = 16;

    public Stack(a) {
        elements = new Object[DEFAULT_INITIAL_CAPACITY];
    }

    /** * push **@param e
     */
    public void push(Object e) {
        ensureCapacity();
        elements[size++] = e;
    }

 /*   *//** * out of stack: there is a leak problem **@return* //* public Object pop() { if (size == 0) throw new EmptyStackException(); return elements[--size]; } * /

    /** ** exit the stack correctly **@return* /
    public Object pop(a) {
        if (size == 0)
            throw new EmptyStackException();
        Object result = elements[--size];
        elements[size] = null;
        return result;
    }

    /** ** */
    private void ensureCapacity(a) {
        if (elements.length == size)
            elements = Arrays.copyOf(elements, 2 * size + 1); }}Copy the code

There is nothing obviously wrong with this program, but it does have a memory leak, and as GC activity increases, or memory usage increases, the performance degradation of the program will show up, which can lead to leaks in severe cases, but these failures are relatively rare.

The main problem with the code is the pop function, assuming that the stack keeps growing, as shown in the figure below

  public Object pop(a) {
        if (size == 0)
            throw new EmptyStackException();
        return elements[--size];
    }
Copy the code

When a large number of POP operations are performed, the GC will not be released because the reference is not null, as shown in the figure below

As you can see from the figure above, if the stack grows and then shrinks, objects thrown from the stack will not be garbage collected. Even if programs no longer use these objects in the stack, they will not be garbage collected because references to the object are still stored in the stack, which is known as expired references. This memory leak is hidden.

Solutions:

Once the references expire, empty them, leaving the references empty.

   public Object pop(a) {
        if (size == 0)
            throw new EmptyStackException();
        Object result = elements[--size];
        elements[size] = null;
        return result;
    }
Copy the code

How to obtain dump files

  1. Dump files of any Java process can be generated using the Jmap tool introduced in the previous chapter.
    • Jmap-dump :live,format=b,file=<filename.hprof> <pid>
  2. Generated by configuring JVM parameters.
  • Option “- XX: + HeapDumpOnOutOfMemoryError” or “- XX: + HeapDumpBeforeFullGC”
  • The option “-xx :HeapDumpPath” means that when OutOfMemory occurs, a dump file will be generated in the corresponding directory. If XX:HeapDumpPath is not specified, dump files are generated in the current directory.
    • Comparison: Using the JMAP +MAT tool is the most common combination, considering that it is almost impossible to analyze them online in a production environment and most of them are done offline.
    • Such as:-Xmx100m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\m.hprof
  1. You can export heap dump files using VisualVM

  1. Using MAT, you can either open an existing heap snapshot or export a heap snapshot directly from an active Java program. This feature lists the currently running Java processes with the help of JPS for selection and taking a snapshot.

5. Use JProfiler to export dump files

In-depth understanding of the JVM family

  • 1. In-depth understanding of the JVM (I) – Introduction and architecture
  • 2. In-depth understanding of the JVM II – 1 classloader subsystem
  • 3. In-depth understanding of THE JVM (III) – Runtime data area (virtual machine stack)
  • 4. In-depth understanding of THE JVM (IV) – runtime data area (program counter + local method stack)
  • 5. In-depth understanding of THE JVM (V) – Runtime data area (heap)
  • 6. In-depth understanding of THE JVM (VI) – Runtime data area (methods area)
  • 7. In-depth understanding of the JVM (vii) – execution engine (interpreter and JIT compiler)
  • 8. An in-depth understanding of the JVM (8) – string constant pool
  • 9. In-depth understanding of JVM (IX) – object instantiation and memory layout
  • 10. In-depth understanding of JVM (x -) – bytecode level profiler execution
  • 11. In-depth understanding of concepts related to JVM (xi) garbage collection
  • 12. In-depth understanding of JVM (xii) – garbage collection algorithms
  • 13. Take a closer look at the JVM (13) – garbage collector
  • 14. Dig deep into the JVM (XIV) one – object distribution map
  • 15. In-depth understanding of the JVM (XV) -class file structure
  • 16. An in-depth understanding of the JVM (XVI) one bytecode instruction set
  • 17. In-depth understanding of the JVM (17) -class lifecycle details
  • 18. Further understanding of the JVM (18) — more about class loaders
  • 19. In-depth Understanding of the JVM (19) – JVM Monitoring and Diagnostics Tools (command line)