preface

If you’ve been working in Java development for years and haven’t used JVM analysis tools, or tried to troubleshoot and tune JVM dump logs for performance, then this is one of your career disappointments and a lack of competence.

This article is based on a tool that comes with the JDK (VisualVM), and then writes a memory overflow case to take you through the introduction of JVM analysis. This article involves the fusion of many knowledge points and actual combat experience sharing, readers can pay attention to it.

VisualVM profile

VisualVM is a Netbeans profile subproject, which comes with JDK6.0 Update 7. It can monitor threads, memory, and view methods’ CPU times and objects in memory, objects that have been GC. Look backwards at the allocation stack (for example, by which 100 strings are allocated).

If you have the CLASspath path configured correctly, starting VisualVM is as simple as typing JVisualVM on the command line to launch the graphical interface. VisualVM supports remote monitoring as well as native monitoring.

Remote monitoring configuration is slightly more complex, and local monitoring is used as an example. As for the production environment, you can choose remote monitoring, or with Mr. Jmap into a dump file, and then download the dump file for analysis.

The VisualVM function interface

After starting VisualVM, let’s look at a few features that help with JVM analysis. The local Idea is used as an example.

An overview of the

After entering VisualVM, click on the process on the left to display the [Overview] content first:

The overview shows information about the JVM, Java version, dump batch, and so on, which can be used to check information in the field. In particular, JVM checks from parameters and system property entries.

I came across a scenario where JVM parameters were not in effect because the JVM parameters were incorrectly written when starting a Java program.

The following instructions, for example, invalidate parameter Settings because JVM parameters are written last.

java -jar app.jar -Xms256m -Xmx512m
Copy the code

The correct way to write this is as follows:

java -Xms256m -Xmx512m  -jar app.jar
Copy the code

In this case, it is easy to see that the JVM parameter does not have a specified parameter value.

monitoring

The monitor screen is one of the most widely used, allowing you to view CPU usage, heap and Metaspace usage, thread usage, class loading, and so on.

By analyzing the usage of heap and Metaspace, we can see the usage and growth of the corresponding memory space, which can be adjusted and planned reasonably.

Click “heap dump” in the upper right corner to generate a dump file based on the time node clicked.

The summary section shows the time node and storage path where the dump file was generated. The main memory analysis we use is in the “Classes” menu on this page.

Enter to see how much memory is occupied by different instances in the heap. Double-click the class name to view “Instance number”, which is the instance details of a specific class.

The most important thing in memory analysis is the number of classes. Now that you know the basics, let’s use an example to simulate an out-of-memory scenario.

Memory overflow scenario construction

Write a bit of code to simulate a memory overflow, creating a Map and adding new objects to it. At the same time during the process of application let the thread sleep or loop to facilitate viewing through VisualVM.

The test code is as follows:

Public class MemoryLeakTest {/** * Declare a cache object */ private static final Map<String, TestMemory> CACHE_MAP = new HashMap<>(); Public static void main(String[] args) {try {// Open visualVm time thread.sleep (10000); } catch (InterruptedException e) { e.printStackTrace(); } // loop for (int I = 0; i < 1000000; i++) { TestMemory t = new TestMemory(); CACHE_MAP.put("key" + i, t); } System.out.println("-------1------"); // Give visualVm time thread.sleep (10000); } catch (InterruptedException e) { e.printStackTrace(); } for(int i=0; i<1000000; i++){ TestMemory t = new TestMemory(); CACHE_MAP.put("key"+i,t); }}}Copy the code

The TestMemory class represents the business class being generated.

public class TestMemory {
}
Copy the code

In order for the program to reach the memory threshold more quickly, we can limit the size of the JVM at startup.

-Xms128m -Xmx128m
Copy the code

In addition, to analyze the memory usage of each region (new generation, old generation) in the memory structure of the heap, the Visual GC plug-in can be installed in the VisualVM Tools, Plug-ins. Use of this plug-in will see the effect later.

With everything in place, let’s verify.

Memory overflow analysis

Let’s start the program and start VisualVM for memory overflow analysis.

As the program executes, we see a rapid increase in “heap” memory.

Metaspace grew along the way.

When we open the Visual GC interface, we will see the heap structure that we have been asked many times in interviews:

In this figure, we can intuitively see the old age, new generation, Metaspace space (JDK8) in the heap memory, as well as Eden, S0(Survivor From) and S1(Survivor To) in the new generation, and their allocation ratio is also intuitively shown. In this form, is it possible to learn the heap memory structure more intuitively?

Here Eden is filled, S0 and S1 are empty, and the old age is almost filled (because garbage collection can’t clean up the objects holding references).

On top of that, you’ll find 3,850 garbage collections for older generations in 20 minutes. This means that frequent Full GC operations have been triggered and memory has not been freed. In production systems, when you see the system running Full GC frequently, that’s a terrible signal from the JVM.

Having said some of the stuff above, now it’s really time for memory analysis. Going back to the “monitoring”, “heap dump”, and “classes” mentioned above, you can see the following image:

As you can see, there are a million TestMemory objects in the heap. When you see a similar number of objects in the heap, you should be aware that there may be a memory leak. That is, a large number of objects are created without being “smoothly” recycled. The reason we didn’t get reclaimed here is because the object was placed inside a static variable.

As mentioned above, you can also double-click the object name further to see the details of the object.

Through the above steps, you can basically locate the object processing problems. At this time, you can go back to the code to troubleshoot the corresponding code, so that you can quickly locate the memory overflow problem. We need to pay special attention to the alarm signals and data rendering provided by VisualVM during the above process.

summary

In this article we are talking about the use of VisualVM, as well as the investigation of online JVM, as well as the memory structure of the JVM, or how to construct a memory overflow (bug) scenario. But it doesn’t matter what you talk about. What matters is what you review, what you learn and what you gain through this article.

The JVM series

I’ve also recently written a series of articles on JVMS that are worth studying.

GC copies live objects, does its memory address change?

How does hashCode Stay The same when an object address changes during GC?