Moment For Technology

JVM memory analysis tool MAT in depth and practice - advanced part

Posted on Aug. 9, 2023, 7:13 a.m. by Purab Datta
Category: The back-end Tag: The back-end java jvm

Note: this article is original, the author and the link of the original article should be marked in forwarding. Welcome to [0 advertising wechat public number: Q's blog].

This series consists of three articles. This is the second advanced part of the series, which explains the core functions, usage and application scenarios of MAT tools in detail, and explains how to solve various memory problems in actual combat scenarios.

  • JVM Memory analysis Tool MAT introduction to MAT product features, basic concepts, comparison with other tools, Quick Start guide.
  • "In-depth Explanation and Practice of JVM Memory Analysis Tool MAT -- Advanced Chapter" expands and explains in detail the core functions, usage and scenarios of MAT tools, and explains them in specific actual combat scenarios to help people deepen their understanding.
  • "JVM Memory analysis tool MAT in-depth explanation and practice -- Advanced chapter" summarizes the systematic analysis of complex memory problems, and through a comprehensive case to improve your practical ability.

1. Introduction

Mastering MAT is a necessary ability for Java masters, but in practice, people often need to face many functions, and they don't know how to start. Xiabian has not found a perfect teaching material, so THIS article helps you to systematically master MAT analysis tools.

This paper explains MAT's many memory analysis tool functions in detail. The combination of these functions is extremely powerful, and skilled use can almost solve all the problems of heap memory offline analysis. We divide the functionality into four categories: memory distribution details, inter-object dependencies, object state details, and retrieval by condition. Each category has multiple function points, and this article explains the scenarios and usage of each function one by one. In addition, original or quoted cases are added to enhance understanding and mastery.

Note: In the opening article of the series,Introduction to JVM memory analysis tool MAT"Introduces the application scenarios and installation methods of MAT. Readers unfamiliar with MAT are advised to read the above and install MAT first. The case in this paper can be easily practiced locally. In addition, the order of product introduction above also corresponds to the organization of function explanation in this paper, as shown below:In order to reduce the confusion of the dazzling menu, you can use the picture below to familiarize yourself with the use entrance of each function, which will be discussed later.

2. Memory distribution and actual combat

2.1 Global Information Overview

Display heap memory size, number of objects, number of classes, number of Class Loaders, number of GC Root, environment variables, thread profile and other global statistics.

Use entry: MAT main screen → Heap Dump Overview.

For example,The following is the number of objects, the number of class loaders, and the number of GC Root.

For example,The following picture shows the overview of threads. You can view the name of each thread, Retained Heap of the thread, and daemon attributes.

Usage Scenario Global overview Displays global statistics and focuses on checking whether abnormal data exists on the whole. Therefore, valid information is limited. The following scenarios can help:

  • When the method area overflows (Java 8 does not use the method area, corresponding to the heap overflow), the number of classes is abnormally large, you can consider whether the dynamic proxy class abnormally loads too much or the class is repeatedly loaded.
  • If the method area overflows, check the number of class Loaders and check whether custom class Loaders are used abnormally.
  • There are too many GC roots and you can look at the GC Root distribution, which is theoretically very rare and only happened to me when JNI was using a buggy library.
  • There are too many threads, usually threads are frequently created but cannot be executed. You can learn about abnormal symptoms from the overview. For specific reasons, you can refer to the thread analysis section of this article, which is not expanded here.

2.2 Dominator tree

Note: the author's Top1 usage frequency is a must-see function for efficient Dump analysis.


  • Across the Retained Heap, the memory size of the Retained Heap can be retrieved by GC.
  • Supports sorting and clustering statistics by package, Class Loader, Super Class and class

Use entrance: Global domination tree: MAT main interface → Dominator Tree

For example, by looking at the Dominator tree in the figure below, you can see that memory is dominated by two threads, ThreadandListholder-Thread and main thread (section 2.6, p. 462).

Usage scenarios

  • When starting a Dump analysis, you should first use the Dominator tree to understand how much memory is controlled by the start objects of each dominating tree, and thus which start objects are the reasons why the GC is unable to free large memory.

  • When the Retained Heap of the dominant tree of a certain object is large and obviously skewed, the dominant relationship of the object with a high proportion can be analyzed and the subtree can be expanded to further locate the root cause of the problem. You can see in the diagram below is ultimately SameContentWrapperContainer hold the ArrayList object is too large.

  • Expand the Dominator tree to view the Dominator path (the difference with the outgoing Reference is that if X dominates Y, Y must be released after X is released. If X only refers to Y, other objects may still refer to Y, and Y cannot be released after X is released, so the Dominator Tree removes a lot of redundant information from the incoming reference.

  • However, there may be some cases where the Retained Heap does not require a large amount of memory. For example, class X has 100 Retained objects, and the Retained Heap of each object is 10 MB. Therefore, the Retained Heap of all the objects in class X is 1 GB. However, the first 20 Dominator tree objects may be from other classes), you can aggregate them by class, package, and class Loader to locate the target.

    • As shown in the figure below, the memory dominated by GC Roots is not large, so aggregation is needed to locate the outbreak point.

    • After displaying in Dominator Tree, aggregate by class as shown below:

    • It can be determined that SomeEntry occupies a large amount of memory, and then further analyze the specific reason based on the code.

  • After some operations are located and an exception is Retained, the direct dominator of the Retained Heap object can be obtained. For example, the object should be recycled from the code.

2.3 Histogram

Note: the author uses frequency Top2


  • List the number of class instances and the cumulative memory ratio of each class instance, including its own Shallow Heap and the retained Heap of the governing object.
  • The url can be sorted by the number of objects, Retained Heap, and Shallow Heap (default sort). Supports regular filtering. Support clustering statistics by package, Class Loader, Super Class and class,

Use the entry: MAT main interface → Histogram; Note that Histogram does not show Retained Heap by default and can be calculated using the calculator icon, as shown below.

Usage scenarios

  • In some cases, the Dominator tree does not display hot objects (as mentioned above, the Dominator Tree does not have a high percentage of the top 20 memory, or there are no obvious hot objects aggregated by class). At this point, it is difficult for the Dominator tree to perform association analysis to determine which category occupies the highest proportion of Retained Heap objects.) At this time, you can use Histogram to view the distribution of the classes of all objects and quickly locate the classes occupying the majority of Retained Heap.
  • Use skills
    • Integer, String, and Object[] generally do not directly cause memory problems. To better organize the view, you can further focus by grouping the class Loader or package, as shown below.
    • Histogram supports filtering using regular expressions. For example, we could show only those classes that match com.q.*.
    • You can continue using the Outgoing Reference in a class of Histogram to view the object distribution to locate which objects are the heads

2.4 Leak Suspects

Function: Automatically detects memory leaks and lists possible memory leak problems.

Use the relevant Suspects: Generally, when there is an obvious memory Leak, it will be shown after analyzing the Dump file, or in the following figure on the MAT homepage → Leak Suspects.

Usage scenario: Check the suspicious objects on the reference chain that occupy a lot of memory. This feature solves some basic problems, but complex ones tend to be of limited help.

For example,

  • The Leak Suspects view below shows that two threads dominate most of the memory.

  • Click on "Details" in the Keywords column above to get Details about the shortest path to GC Root and dominator path.

2.5 Top Consumers

Features: Maximum object reports, which show which classes, class Loaders, and packages occupy the highest percentage of memory, are also supported by Histogram and Dominator Tree.

Usage scenario: When an application has a memory leak, check which leaked objects usually account for a large portion of the Dump snapshot. Therefore, it is of high value for simple problems.

2.6 Comprehensive Case 1

Use utility items: Heap Dump Overview, Dominator Tree, Histogram, Class Loader Explorer (see Section 3.4), and Incoming References (see Section 3.1)

The program code

package com.q.mat;

import java.util.*;
import org.objectweb.asm.*;

public class ClassLoaderOOMOps extends ClassLoader implements Opcodes {

    public static void main(final String args[]) throws Exception {
        new ThreadAndListHolder(); // The ThreadAndListHolder class loads large objects

        ListClassLoader classLoaders = new ArrayListClassLoader();
        final String className = "ClassLoaderOOMExample";
        final byte[] code = geneDynamicClassBytes(className);

        // Loop to create a custom class loader and load ClassLoaderOOMExample
        while (true) {
            ClassLoaderOOMOps loader = newClassLoaderOOMOps(); Class?  exampleClass = loader.defineClass(className, code,0, code.length); // Load the binary stream into memory
            // exampleClass.getMethods()[0].invoke(null, new Object[]{null}); // Perform the auto-loading class method by calling main via reflection}}private static byte[] geneDynamicClassBytes(String className) throws Exception {
        ClassWriter cw = new ClassWriter(0);
        cw.visit(V1_1, ACC_PUBLIC, className, null."java/lang/Object".null);

        // Generate the default constructor
        MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "init"."()V".null.null);

        // Generate bytecode instructions for the constructor
        mw.visitVarInsn(ALOAD, 0);
        mw.visitMethodInsn(INVOKESPECIAL, "java/lang/Object"."init"."()V");

        // Generate the main method
        mw = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main"."([Ljava/lang/String;)V".null.null);
        // Generate bytecode instructions in the main method
        mw.visitFieldInsn(GETSTATIC, "java/lang/System"."out"."Ljava/io/PrintStream;");

        mw.visitLdcInsn("Hello world!");
        mw.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream"."println"."(Ljava/lang/String;) V");
        mw.visitEnd();  // Bytecode generation is complete

        return cw.toByteArray();  // Get the binary stream corresponding to the generated class file}}Copy the code
package com.q.mat; import java.util.*; import org.objectweb.asm.*; public class ThreadAndListHolder extends ClassLoader implements Opcodes { private static Thread innerThread1; private static Thread innerThread2; private static final SameContentWrapperContainerProxy sameContentWrapperContainerProxy = new SameContentWrapperContainerProxy(); Static {// Enable two threads as GC Roots innerThread1 = new Thread(new Runnable() {public void run() { SameContentWrapperContainerProxy proxy = sameContentWrapperContainerProxy; try { Thread.sleep(60 * 60 * 1000); } catch (Exception e) { System.exit(1); }}}); innerThread1.setName("ThreadAndListHolder-thread-1"); innerThread1.start(); innerThread2 = new Thread(new Runnable() { public void run() { SameContentWrapperContainerProxy proxy = proxy = sameContentWrapperContainerProxy; try { Thread.sleep(60 * 60 * 1000); } catch (Exception e) { System.exit(1); }}}); innerThread2.setName("ThreadAndListHolder-thread-2"); innerThread2.start(); } } class IntArrayListWrapper { private ArrayListInteger list; private String name; public IntArrayListWrapper(ArrayListInteger list, String name) { this.list = list; = name; }} class SameContentWrapperContainer {/ / 2 internal point to the same Wrapper ArrayList, Dominator tree IntArrayListWrapper intArrayListWrapper1 IntArrayListWrapper intArrayListWrapper2; Public void init() {// The thread governs the arrayList directly. Neither IntArrayListWrapper governs the arrayList. ArrayListInteger ArrayList = generateSeqIntList(10 * 1000 * 1000, 0); intArrayListWrapper1 = new IntArrayListWrapper(arrayList, "IntArrayListWrapper-1"); intArrayListWrapper2 = new IntArrayListWrapper(arrayList, "IntArrayListWrapper-2"); } private static ArrayListInteger generateSeqIntList(int size, int startValue) { ArrayListInteger list = new ArrayListInteger(size); for (int i = startValue; i  startValue + size; i++) { list.add(i); } return list; } } class SameContentWrapperContainerProxy { SameContentWrapperContainer sameContentWrapperContainer; public SameContentWrapperContainerProxy() { SameContentWrapperContainer container = new SameContentWrapperContainer(); container.init(); sameContentWrapperContainer = container; }}Copy the code
Startup parameters: -Xmx512m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/Users/gjd/Desktop/dump/heapdump.hprof -XX:-UseCompressedClassPointers -XX:-UseCompressedOopsCopy the code

Reference diagram

The analysis process

  1. First enter the Dominator tree, you can see objects and the main thread is SameContentWrapperContainerProxy both hold 99% memory cannot release lead to OOM.
  2. The Number of class loaders is more than 500,000, which is basically an exception, as shown in the following figure.
  3. Using the Class Loader Explorer analysis tool, the Class loading details are displayed, and 524061 Class Loaders are displayed. In our case, we only have a custom class loader like ClassLoaderOOMOps, so we can quickly locate the problem.
  4. If there are many class loaders and it is not clear which is causing the problem, you can cluster all class Loader objects by class, as shown in the figure below.
  5. Histogram aggregates its Retained Heap and Retained Heap by class and shows the order of magnitude of the object (if the Retained Heap item is empty, you can calculate the Retained Heap by clicking on the computer icon below). You can see that ClassLoaderOOMOps has 524,044 objects and its Retain Heap occupies more than 370M (about 100M in the code above).
  6. Using incoming References, you can find the location of the created code.
  7. In the second direction, the Obejct array, which occupies 319M of memory, also uses incoming References to check the reference path, making it easy to locate the specific code location. As you can see from the following figure, the starting point of the Dominator tree is not necessarily the GC root, and the initial creation path may not be available from the Dominator Tree, but incoming References are available.

3. Detailed description and practice of dependency between objects

3.1 the References

Note: the author uses frequency Top2

Function: View all references to a particular object in the object reference graph (provides references to other objects or primitive types, as well as references to other external objects). Complete dependency link details are provided through direct and indirect reference details (mainly attribute values and memory usage) of any object.

Access: Target domain right-click → List objects → With Outgoing References /with Incoming References.

Usage scenarios

  • Outgoing Reference: views the object referenced by the object and supports chain passing operations. For example, if the Retained Heap of a complex object is large, you can use the outgoing reference to check which attribute is caused by the Retained Heap of a complex object. In the following figure, A dominates F, and F occupies A large amount of memory. However, the directly dominated object A of F cannot be modified during optimization. We can view D, B, E, and C on the relationship chain through outgoing Reference, and optimize the intermediate links with business logic, which cannot be done by relying on dominator tree.
  • Incoming reference: Checks which objects an object is referenced by and supports chain delivery. As shown in the following figure, K occupies a large memory, so the Retained Heap of J is large. The goal is to remove J reference from GC Roots, but J is the root of Dominator tree, so the path of its reference cannot be obtained. The incoming reference allows you to view H, X, and Y in the relationship chain and remove J from the GC Root chain in combination with business logic.

3.2 the Thread the overview

Operation: Displays detailed status of the execution stack of a thread and the object referenced by the thread stack, as well as associated memory information such as Retained Heap of each thread.

Entry: MAT home page → Thread Overview

Usage scenarios

  • Look at the percentage of memory held by different threads to locate high memory consumption threads (development tips: Do not use Thread or Executor default Thread names directly. Avoid mixing them all together. Use your own Thread names to make it easier to identify.
  • Threadandlistholder-thread is blocked in the sleep method as shown in the following figure.

3.3 Path To GC Roots

Function: Provides details about the path of any object to GC Root.

Use entry: Target domain right-click → Path To GC Roots

Usage scenario: Sometimes you are sure that you have handled a large collection of objects but still cannot collect them. This feature can quickly locate the reason why the exception object cannot be collected by the GC, directly hitting the reference path of the exception object to the GC Root. The advantage of incoming Reference over Dominator Tree is that it blocks many unnecessary references, and the advantage of Dominator tree is that it can get more comprehensive information.

Tip: Exclude all phantom/weak/soft etc. References when checking for memory leaks, it is recommended to exclude all phantom/weak/soft references from the references chain, because the objects that are virtual /weak/soft references can be recycled directly by GC. Focus on whether the object still has a Strong reference chain.

3.4 Class Loader Analysis


  • Check the usage of all class Loaders in the heap (entry: MAT home menu blue bucket icon, Java Basics, Class Loader Explorer).
  • View Classes in the heap that are Duplicated by different Class Loaders (entry: MAT home menu blue bucket icon → Java Basics → Duplicated Classes).

Usage scenarios

  • This parameter is used when you learn from the Heap dump Overview that too many Class Loaders occupy memory abnormally and perform more detailed analysis to locate the cause.
  • Resolve NoClassDefFoundError problems or check if jar packages are being reloaded

The specific usage method is introduced in the cases of 2.6 and 3.5.

3.5 Comprehensive Case 2

Use tools: Class Loader (duplicate class detection), Inspector, re search.

NoClassDefFoundError is run. There are two different versions of the same class in the classpath.

The analysis process

  1. Enter the repeated class detection function loaded by MAT, as shown in the following figure.

  2. You can see all the duplicate classes, and the associated class loaders, as shown below.

  3. By class name, enter the class name in the box to filter out invalid information.

  4. If you select the target class, you can see in the Inspector view which JAR the loaded class is in. (In this example, the repeated class is loaded by the URLClassloader. Right click on the "_context" property and finally click "Go Into". In the pop-up window, the property "_war" value is the specific package location of the loaded class.)

4. Object state explanation and actual combat

4.1 inspector

Function: MAT displays detailed information of objects through inspector panel, such as static attribute value and instance attribute value, memory address, class inheritance relationship, package, class Loader, GC Roots and other detailed data.

Usage scenarios

  • In scenarios where the memory usage is strongly related to the business logic, the inspector allows you to view specific object property values. For example, in a social networking scenario, the friend List of a user object is abnormal, and the List length reaches several hundred million. The inspector panel obtains the abnormal user ID, and then continues to check which user belongs to from a business perspective. In this case, there may be a system account and all users are friends.
  • Collections are used more often, for example by looking at the size property of an ArrayList.

For example,The Inspector window on the left shows details of the ArrayList instance at address 0x125754CF8, including basic properties such as modCount that are not shown in outgoing References.

4.2 Set Status

Function: Help you intuitively understand the memory usage of the system and find the wasted memory space.

Use entrance: MAT home page → Java Collections → Fill rate /Hash conflict and other functions.

Usage scenarios

  • The memory waste caused by sparse or empty collection objects such as ArrayLists or arrays can be located by clustering them according to fill rate.
  • Determine the hash policy based on the HashMap conflict rate.

The specific application method is described in detail in section 4.3.

4.3 Comprehensive Case 3

Use tool items: Dominator Tree, Histogram, and Aggregate Ratio.

Abnormal Phenomenon: The program is OOM, and there is no large object in Dominator Tree. According to Histogram, multiple ArrayList occupies a large amount of memory, and it is expected to reduce the ArrayList optimization program.

The program code

package com.q.mat;

import java.util.ArrayList;
import java.util.List;

public class ListRatioDemo {

    public static void main(String[] args) {
        for(int i=0; i10000; i++){ Thread thread =new Thread(new Runnable() {
                public void run(a) {
                    HolderContainer holderContainer1 = new HolderContainer();
                    try {
                        Thread.sleep(1000 * 1000 * 60);
                    } catch (Exception e) {
                        System.exit(1); }}}); thread.setName("inner-thread-"+ i); thread.start(); }}}class HolderContainer {
    ListHolder listHolder1 = new ListHolder().init();
    ListHolder listHolder2 = new ListHolder().init();

class ListHolder {
    static final int LIST_SIZE = 100 * 1000;
    ListString list1 = new ArrayList(LIST_SIZE); / / 5% fill
    ListString list2 = new ArrayList(LIST_SIZE); / / 5% fill
    ListString list3 = new ArrayList(LIST_SIZE); / / 15% fill
    ListString list4 = new ArrayList(LIST_SIZE); / / 30% fill

    public ListHolder init(a) {
        for (int i = 0; i  LIST_SIZE; i++) {
            if (i  0.05 * LIST_SIZE) {
                list1.add("" + i);
                list2.add("" + i);
            if (i  0.15 * LIST_SIZE) {
                list3.add("" + i);
            if (i  0.3 * LIST_SIZE) {
                list4.add(""+ i); }}return this; }}Copy the code

The analysis process

  1. There is no high percentage starting point using the Dominator Tree.
  2. By using Histogram, it is found that ListHolder and ArrayList occupy a high proportion, and many lists have a low fill rate and waste memory after business analysis.
  3. Check the Fill rate of ArrayList, MAT homepage → Java Collections → Collection Fill Ratio.
  4. View type fill in java.util.arrayList.
  5. It can be seen from the results that most of the initial application lengths of ArrayList are too large.

5. Search details and actual combat according to conditions

5.1 OQL

Function: provides an object (class) level unified structured query language similar to SQL to filter objects in the heap according to conditions.


SELECT * FROM [ INSTANCEOF ] class_name [ WHERE filter-expression ]
Copy the code
  • The Select clause can use '*' to view the referenced instance of the resulting object (equivalent to outgoing References). You can specify specific content, such as Select OBJECTS v. lementData from xx to return the complete object, rather than simple object description information); You can use the Distinct keyword for deduplication.
  • From Specifies the query scope. Generally, specify the class name, regular expression, and object address.
  • Where is used to specify the filter criteria.
  • For the syntax, see OQL Syntax
  • Unsupported core functions: Group by Value. If necessary, you can generate the results into CSV and then use awK and other script tools for analysis.
  • Select * from java.util.ArrayList where size=0 and modCount=0

Usage scenarios

  • OQL is often used for more complex problems that have a lot to do with business logic. For example, a large number of small objects occupy a large amount of memory, but it is not expected to be too many small objects (for example, up to one million). It is unrealistic to look at them one by one. You can use OQL query to export data for troubleshooting.
  • Example: The distributed link tracking system of microservices collects all interface names of each service. There are 200 services in total, but 2 million interface names are collected (a service does not have 10,000 interfaces). At this time, it is difficult to locate them by directly viewing them in the List one by one, so you can directly export them with OQL. Locate which service interface name collection exception (e.g., the ID in the URL is also counted in the interface)

5.2 Retrieval and screening

Functions: The second chapter of this paper memory distribution, the third chapter of the object dependence between many functions, support by string retrieval, by regular retrieval operations.

Usage Scenario: When using functions such as Histogram and Thread Overview, string matching and regular matching condition filtering can be further added to narrow the scope of investigation.

5.3 Addressing by Address

Function: Lookup an object based on its virtual memory hexadecimal address.

Usage scenario: Only when you know the address and want to quickly view the object for subsequent analysis, you can directly use outgoing Reference to learn about the object information.

5.4 Comprehensive Case 4

Use utility items: OQL, Histogram, and Incoming References

Symptom and Purpose: The program occupies a large memory and initializes a long ArrayList by default. You need to analyze the proportion of the Used ArrayList, whether the lazy loading mode is adopted by data support, and which code creates an empty ArrayList.

The program code

public class EmptyListDemo {
    public static void main(String[] args) {
        EmptyValueContainerList emptyValueContainerList = new EmptyValueContainerList();
        FilledValueContainerList filledValueContainerList = new FilledValueContainerList();
        System.out.println("start sleep...");
        try {
            Thread.sleep(50 * 1000 * 1000);
        } catch (Exception e) {
            System.exit(1); }}}class EmptyValueContainer {
    ListInteger value1 = new ArrayList(10);
    ListInteger value2 = new ArrayList(10);
    ListInteger value3 = new ArrayList(10);

class EmptyValueContainerList {
    ListEmptyValueContainer list = new ArrayList(500 * 1000);

    public EmptyValueContainerList(a) {
        for (int i = 0; i  500 * 1000; i++) {
            list.add(newEmptyValueContainer()); }}}class FilledValueContainer {
    ListInteger value1 = new ArrayList(10);
    ListInteger value2 = new ArrayList(10);
    ListInteger value3 = new ArrayList(10);

    public FilledValueContainer init(a) {
        return this; }}class FilledValueContainerList {
    ListFilledValueContainer list = new ArrayList(500);

    public FilledValueContainerList(a) {
        for (int i = 0; i  500; i++) {
            list.add(newFilledValueContainer().init()); }}}Copy the code

The analysis process

  1. There are 500,000 empty ArrayList instances in memory with Capacity = 10. Let's examine the total memory footprint of these objects and where they were created to see if lazy initialization (i.e., not instantiating these objects until they are used, otherwise null) is necessary.

  2. Use OQL to query the ArrayList (size=0 and modCount=0) that is not used after initialization. You can see that there are 1.5 million empty ArrayLists, and these objects are wasted memory. Let's calculate the total memory footprint and see if we need to optimize it based on the results.

  3. To calculate the total memory of 1.5 million ArrayLists, click directly on the Histogram icon with the yellow arrow at the top right, which is shown as a Histogram of selected results. This totals about 120MB of memory (so click on the results here, Does not contain modCount or ArrayList objects whose size is greater than 0).This type of continued analysis of selected results is supported by many functions, such as regular retrieval, Histogram, Dominator Tree, and so on.

  4. Take a look at the exact source of the empty ArrayList using incoming References, as shown in the figure below for a clear object creation path.

Conclusion outlook

So far, this paper explains the functions, use methods and application scenarios of MAT tools, as well as four practical cases, which are of great benefit to the analysis of JVM memory problems, especially the combination of various functions. A systematic approach to JVM heap memory analysis will be summarized and practiced in more complex cases in the next article, MAT in Depth and Practice.

Refer to the content

Welcome to forward, follow, the author's wechat official account:Q's blog.Irregular delivery of dry goods, practical experience, system summary, source code interpretation, technical principles.

About (Moment For Technology) is a global community with thousands techies from across the global hang out!Passionate technologists, be it gadget freaks, tech enthusiasts, coders, technopreneurs, or CIOs, you would find them all here.