This is the third day of my participation in the Novembermore Challenge

preface

Today I suddenly received a service container alarm, the memory has reached 90% of the alarm line. Just a few days ago, a big requirement was posted, and the first reaction was that the code of this new module had a memory leak. This article discusses how to find memory leaks, how to locate memory leaks in the code, and finally how to solve memory leaks.

MAT

The best tool for analyzing JVM Memory problems, in my opinion, is Memory Analyzer. Support HTML page to view memory information.

With this preview, if there is a leak, the Problem Suspect will show you how many percent it is. The thread pool is friend-thread-pool. If a project code has multiple business modules, it is recommended that each business module define its own thread pool, which can not only achieve thread isolation, but also facilitate our later troubleshooting. This Narrows our code down to business modules that use a friend-Thread-pool thread pool.

Click Details » to see the Details

You can see that there are 125,018 MemberSubDTO classes, and ArrayList and CopyOnWriteArrayList take up a lot of memory. It’s not hard to figure outList<MemberDTO>There’s something wrong with this code. This allows you to locate the exact code

private void initAppAndHistorySub(Long accountId, List<MemberDTO> subList) { List<MemberDTO> historySubList = Lists.newCopyOnWriteArrayList(); List<MemberDTO> onlineSubList = Lists.newCopyOnWriteArrayList(); subList.parallelStream().forEach(memberDTO -> { MemberDTO btUserDTO = UserFeignImpl.get().getBtEntryInfoByAccountId(memberDTO.getAccountId(), false); if (Objects.nonNull(btUserDTO)) { historySubList.add(memberDTO); } else { onlineSubList.add(memberDTO); }}); List<MemberDTO> intersectionAppAndBtSubList = new ArrayList<>(onlineSubList); initOnlineSub(accountId, onlineSubList, intersectionAppAndBtSubList); initHistorySub(accountId, historySubList); }Copy the code

We’re using a concurrent stream for the list, and for thread-safety purposes, we’re using CopyOnWriteArrayList. The usage scenario of CopyOnWriteArrayList is ignored. CopyOnWriteArrayList is, as its name suggests, an ArrayList that satisfies CopyOnWrite. When modifying a piece of memory, write operations are performed not in the original memory block but in a copy of the memory, and write operations are performed in the new memory. After the write, the pointer to the original memory points to the new memory, and the original memory can be reclaimed. When there are many write operations, the memory will always copy, naturally OOM. So CopyOnWriteArrayList is not good for writing more and reading less, which is what we’re doing here. Once you know why, you can change your code. Without parallelStream, there is no thread safety, and CopyOnWriteArrayList is no longer necessary.

conclusion

When using CopyOnWriteArrayList, it is important to consider the use scenario, and not just use CopyOnWriteArrayList when encountering thread safety issues. It is also a useful trick for each business module to define its own thread pool.