In-depth understanding of JVM (eight)-java heap analysis

In-depth understanding of JVM (eight)-java heap analysis The
previous section introduced monitoring tools for JVM, including JPS can view all current java processes, jstack view thread stack can help you analyze whether there are deadlocks, etc., jmap can be exported The java heap file is analyzed on the MAT tool and so on. These tools are very useful, but to use them well requires continuous practical analysis. This article will introduce a case of java heap analysis using MAT tool.

Causes of Out of Memory (OOM)

Our common cause of OOM (Out Of Memory Error) is not just heap memory overflow, heap memory overflow is only one of OOM situations, OOM may also occur in metaspace, thread stack, and direct memory.

The following demonstrates the occurrence of OOM in each area:

Heap OOM

public static void main(String[] args)
    {
        List<Byte[]> list=new ArrayList<Byte[]>();
        for(int i=0;i<100;i++){
            //构造1M大小的byte数值
            Byte[] bytes=new Byte[1024*1024];
            //将byte数组添加到list列表中,因为存在引用关系所以bytes数组不会被GC回收
            list.add(bytes);
        }
    }

The above program sets the maximum heap memory to 50M, and executes:
Insert picture description here
Insert picture description here
Obviously, the program will occupy 100M of heap space through the loop, which exceeds the set 50M, so OOM of the heap memory occurs.

For this OOM, the solution is to increase the heap memory space, remove the reference relationship when necessary in actual development, so that the garbage collector can reclaim useless objects as soon as possible.

Metaspace OOM

public static void main(String[] args) throws Exception
    {
        for(int i=0;i<1000;i++){
            //动态创建类
            Map<Object,Object> propertyMap = new HashMap<Object, Object>();  
            propertyMap.put("id", Class.forName("java.lang.Integer"));    
            CglibBean bean=new CglibBean(propertyMap);
            //给 Bean 设置值    
            bean.setValue("id", new Random().nextInt(100));  
            //打印 Bean的属性id
            System.out.println("id=" + bean.getValue("id"));    
        }
    }

The above code dynamically creates classes through Cglib and sets the metadata area size to 4M:
Insert picture description here
Because the code creates classes in a loop, a large amount of class metadata is stored in the metadata area and exceeds the set 4M space, so the metadata area OOM is reported:
Insert picture description here
solve the OOM The method is to increase the value of the MaxMetaspaceSize parameter, or simply not set this parameter. By default, the memory that can be used by the metaspace will be limited by the local memory.

Stack OOM

When creating a new thread, the JVM will allocate stack memory to each thread. When creating too many threads, the more memory is occupied. In this case, OOM may occur:

public static void main(String[] args) throws Exception {
        //循环创建线程
        for (int i = 0; i < 1000000; i++) {
            new Thread(new Runnable() {
                    public void run() {
                        try {
                            //线程sleep时间足够长,保证线程不销毁
                            Thread.sleep(200000000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
            System.out.println("created " + i + "threads");
        }
    }

Insert picture description here
Obviously, the solution to this OOM is to reduce the number of threads.

Direct memory OOM

public static void main(String[] args) throws Exception {      
        for (int i = 0; i < 1000000; i++) {
            //申请堆外内存,这个内存是本地的直接内存,并非java堆内存
            ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024*1024*1024);
            System.out.println("created "+i+" byteBuffer");
        }
    }

The allocateDirect method of ByteBuffer can apply for direct memory. When the applied memory exceeds the local available memory, it will report OOM: The
Insert picture description here
solution to this OOM is to use off-heap memory appropriately, and explicitly perform garbage collection if necessary. (That is, execute System.gc() in the code;)

Added:,
直接内存是除Java虚拟机之外的内存 but it may also be used by Java.

It can directly allocate memory outside the Java virtual machine by calling a local method , and then directly manipulate the memory through a DirectByteBuffer object stored in the Java heap , without first copying the data in the external memory to the heap and then operating, thereby improving Improve the efficiency of data operations.

The size of direct memory is not controlled by the Java virtual machine, but since it is memory, an OOM exception will be thrown when the memory is insufficient.

Direct memory (off-heap memory) and heap memory are compared.
Direct memory application space consumes higher performance, especially when a certain amount is frequently applied for
. The performance of direct memory IO read and write is better than ordinary heap memory, in multiple reads and writes The difference is obvious in the case of operation

Comparison of off-heap memory and on-heap memory:
Advantages :
  1 Reduce the work of garbage collection, because garbage collection will suspend other work (may use multi-threading or time slicing, you can't feel it at all)
  2 Speed ​​up the copy speed. Because when flushing from the heap to the remote, it will first be copied to the direct memory (non-heap memory) and then sent; while the off-heap memory is equivalent to omitting this work.
Disadvantages
1. Off-heap memory is difficult to control. If memory leaks, it is difficult to troubleshoot.
2. Off-heap memory is relatively unsuitable for storing complex objects. Generally simple objects or flat ones are more suitable.

MAT tool usage

When the java application fails, we may need to use MAT to analyze the problem and find out the cause of the problem. Here is a case to introduce the use of MAT:

Preparation:
We use the jmap tool or jvisualvm to export a heap snapshot file from the program running environment in advance.
Use the MAT tool to open:
Insert picture description here
We found that the object that occupies the most memory is AppClassLoader. We know that AppClassLoader is the class used to load the application, so we further look at the objects it references.
Insert picture description here
The following figure shows the space usage of the object referenced by AppClassLoader. "Shallow Heap" represents the size of the shallow heap . The shallow heap is the space occupied by the class itself, that is, the size of the metadata of the class itself. "Retained Heap" represents the size of the deep heap, which represents the sum of the space occupied by this class and other classes it references, and also the amount of space that can be released after the class is garbage collected . (If the class is recycled, the object it refers to will become unreachable and therefore will be recycled)
Insert picture description here
Continue to look at the object that occupies the largest deep heap.
Insert picture description here
It can be seen from the above figure that the reason for the relatively large deep heap is that the program contains an ArrayList, which contains a large number of String objects, and each String object has a size of 80216 bytes.

Therefore, the analysis of this heap is basically clear, because the program includes a large number of String objects, and they are in the ArrayList, the reference relationship always exists, so they cannot be garbage collected, resulting in OOM.

MAT other function description

In addition to the MAT function we used above, there are some functions that are also frequently used.

Histogram:显示每个类使用情况以及占用空间大小。

Insert picture description here
The above figure shows that the char[] class has 1026 objects, occupying 5967480 bytes of space. Through the above analysis, it is concluded that the String object occupies most of the space, and the internal storage of the Stirng object uses char[] to It is stored, so it is understandable that the shallow heap size of char[] is shown here as 5967480 bytes.

Thread_overview:显示线程相关的信息。

Insert picture description here

OQL:通过类似SQL语句的表达式查询对象信息。

Insert picture description here
The above figure uses the OQL statement to query the String object that matches 123 in the string.

Conclusion

This article first introduces several situations of OOM in java programs, and then introduces the basic usage of MAT through simple cases.

Guess you like

Origin blog.csdn.net/eluanshi12/article/details/82757312