OOM, don't panic. I'll teach you how to locate

Keywords: Java snapshot Eclipse Tomcat

This slag is writing BUG this morning. A problem has been thrown by TL. It is said that there is something wrong with the platform that makes me healthy. After an operation finds the error log, I'm foolishly out of memory error. I can also write this thing, but I haven't located it.

org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is java.lang.OutOfMemoryError: Java heap space
	at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:446)
	at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:378)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:475)	
Caused by: java.lang.OutOfMemoryError: Java heap space

So habitually opened Baidu. After reading some experience, I'm ready to start. The steps are as follows:

  1. First find the OO error snapshot under the server
  2. Use tools to analyze the causes of errors
  3. Locate the place where the exception occurs in combination with the code

Find error snapshot

Don't understand what heap dump looks like: https://www.jianshu.com/p/91ee6476848c

Mine is here

Of course, you can find it through the find command, usually in the tomcat directory

At the end of hprof is the target file

Use tool analysis

MemoryAnalyzer.exe

Download link: https://www.eclipse.org/mat/downloads.php (it is suggested to go online scientifically, about 70M)

After opening, import the snapshot file found in the previous step. Note that there may be a pit (generally, the snapshot file of online environment is always on G, so it is recommended to increase the maximum memory of the tool, as follows)

MemoryAnalyzer.ini file. My file is 4.1G, so it's larger.

-startup
plugins/org.eclipse.equinox.launcher_1.5.0.v20180512-1130.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.win32.win32.x86_64_1.1.700.v20180518-1200
-vmargs
-Xmx5096m

After importing successfully, you will go to the welcome interface. Just ignore it. Click the leaksuspects generated by analysis, as shown in the figure:

Histogram is commonly used:

Memory consumption ranking is also helpful for positioning. There is an error message at the bottom of the pie chart, which is generated automatically. It mainly shows the high memory consumption, which means that your problem is here.

First, look at the stack information to find the error reporting place. Here is the specific error reporting method information (I didn't cut all):

Let's see what is caused by the object. Click details

You can see that there are nearly 10 million objects in total, and the later memory is also used. Then you can find them in the code at this step.

Lookup code

 @Override
    public List<ResourceResp> queryResources(ResourcesVerifyReq resourcesVerifyReq) {
        try {
            ResponseData responseData;
            long total = 1001;
            HashMap<String, Object> queryParam = new HashMap<>(8);
            int pageNo = resourcesVerifyReq.getPageNo();
            queryParam.put("pageNo", pageNo);
            int pageSize = resourcesVerifyReq.getPageSize();
            queryParam.put("pageSize", pageSize);

            if (pageSize > 0) {
                responseData = RpcExchange.call(rpcParamDto,  queryParam,  Constants.HTTP_WEB_PORT);
            } else {
                pageSize = 1000;
                queryParam.put("pageSize", pageSize);
                while ((long) pageNo * (long) pageSize < total) {
                    responseData = RpcExchange.call(rpcParamDto, queryParam,  Constants.HTTP_WEB_PORT);
                    List<ResourceResp> list = data.getList();
                    total = data.getTotal();
                    returnData.addAll(list);
                }
            }
            return returnData;
        } catch (Exception e) {
            logger.error("Resource query error",e);
        }
    }
//I'm sure that when you see this while loop, you are also shocked. It turns out that when the total is greater than 1000 after query, there will be a dead loop here. The reason is that pageNo does not perform incremental operation when paging to query.

Amend to read:

while ((long) pageNo * (long) pageSize < total) {
                    responseData = RpcExchange.call(rpcParamDto, queryParam,  Constants.HTTP_WEB_PORT);
                    List<ResourceResp> list = data.getList();
                    total = data.getTotal();
                    returnData.addAll(list);
                    // When it is greater than 1000, it needs to be incremented
                    queryParam.put("pageNo", ++pageNo);
                }

The summary is as follows:

//1. When writing a loop, try to consider whether the number of times is clear, whether the termination conditions are fixed, be careful of the dead loop, be careful of the dead loop, and be careful of the dead loop
 //2. When positioning OOM, don't panic. Tools do a lot of work for us, but you need to be able to use them. I just used my fur
 //3. During the review, pay more attention to the places that may lead to the dead cycle
 //4. The orientation of OOM and other powerful tools need to be contacted more

 

59 original articles published, 31 praised, 10000 visitors+
Private letter follow

Posted by FRSH on Thu, 16 Jan 2020 20:14:32 -0800