On JVM memory structure heap

5.1 definition

Heap reactor

  • With the new keyword, heap memory is used when creating objects

  • Thread sharing, objects in the heap need to consider thread safety

  • There is garbage collection mechanism

  • Java Heap is the largest piece of memory managed by Java virtual machine, also known as "GC heap". It is a memory area shared by all threads and created when the virtual machine starts.

  • The only purpose is to store object instances and arrays (JDK7 has moved string constant pools and class static variables to the Java heap), and almost all object instances will be stored and allocated in the heap. With the development of JIT compiler, optimization techniques such as escape analysis, stack allocation, scalar substitution and so on lead to not all objects will be allocated on the heap.

  • The Java heap is the primary area of garbage collector management. The heap memory can be divided into three regions: Eden, From Survivor and To Survivor.

5.2 heap memory overflow

If the Java heap cannot request enough memory when trying to expand memory, the Java virtual machine will throw an OutOfMemoryError exception.

Question: since there is a garbage collection mechanism, why does heap memory overflow occur?

Answer: garbage collection mechanism is to recycle unused objects. When an object is referenced or indirectly referenced, it will not be garbage collected, resulting in more and more memory consumption and memory overflow.

Sample code

/**
 * -Xmx8m  Adjust the maximum heap memory to 8m
 */
public class Demo {

    public static void main(String[] args) {
        int i = 0;
        try {
            List<Object> list = new ArrayList<>();
            String a = "hello";
            while (true) {
                list.add(a);
                a = a + a;
                i++;
            }
        } catch (Throwable e) {
            e.printStackTrace();
            System.out.println(i);
        }
    }

}

output

java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Arrays.java:3332)
    at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:124)
    at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:448)
    at java.lang.StringBuilder.append(StringBuilder.java:136)
    at com.loksail.learndemo.Demo.main(Demo.java:18)
17

By adjusting the maximum heap memory to 8m, when the list is added to the 18th element, there is a memory overflow. The main reason is that the list set is always in use in the program, and the String objects that are constantly created are also referenced by the list set, so they cannot be garbage collected. As a result, the memory occupied by the list set is larger and more String objects are more and more, and the OutOfMemoryError exception is thrown .

5.3 heap memory diagnostics

5.3.1 jps tool

See which java processes are in the current system

[root@iZwz9d10hr1juhw84f6r31Z ~]# jps
1237 AgentDaemon
27773 es-yxfbp-main-1.0.0.jar
2974 Jps

5.3.2 jmap tool

  • View the current heap memory usage

    jmap heap process id
    

    Sample code

    public class Demo {
    
      public static void main(String[] args) throws InterruptedException {
          System.out.println("1...........");
          Thread.sleep(20000L);
          byte[] bytes = new byte[1024 * 1024 * 10];  //10m
          System.out.println("2...........");
          Thread.sleep(10000L);
          bytes = null;
          System.gc();
          System.out.println("3...........");
          Thread.sleep(100000000L);
      }
    
    }
    

    View current process number

    D:\JWF\Gitee\learn-demo\src\main\java\com\loksail\learndemo>jps
    15380 Demo
    12840 Launcher
    17000 Jps
    3928
    10012 Launcher
    

    When printing 1 . memory output after

    D:\JWF\Gitee\learn-demo\src\main\java\com\loksail\learndemo>jmap -heap 15380
    Attaching to process ID 15380, please wait...
    Debugger attached successfully.
    Server compiler detected.
    JVM version is 25.221-b11
    
    using thread-local object allocation.
    Parallel GC with 4 thread(s)
    
    Heap Configuration:
     MinHeapFreeRatio         = 0
     MaxHeapFreeRatio         = 100
     MaxHeapSize              = 4261412864 (4064.0MB)
     NewSize                  = 88604672 (84.5MB)
     MaxNewSize               = 1420296192 (1354.5MB)
     OldSize                  = 177733632 (169.5MB)
     NewRatio                 = 2
     SurvivorRatio            = 8
     MetaspaceSize            = 21807104 (20.796875MB)
     CompressedClassSpaceSize = 1073741824 (1024.0MB)
     MaxMetaspaceSize         = 17592186044415 MB
     G1HeapRegionSize         = 0 (0.0MB)
    
    Heap Usage:
    PS Young Generation
    Eden Space:
     capacity = 66584576 (63.5MB)
     used     = 6658584 (6.350120544433594MB)
     free     = 59925992 (57.149879455566406MB)
     10.00018983375369% used
    From Space:
     capacity = 11010048 (10.5MB)
     used     = 0 (0.0MB)
     free     = 11010048 (10.5MB)
     0.0% used
    To Space:
     capacity = 11010048 (10.5MB)
     used     = 0 (0.0MB)
     free     = 11010048 (10.5MB)
     0.0% used
    PS Old Generation
     capacity = 177733632 (169.5MB)
     used     = 0 (0.0MB)
     free     = 177733632 (169.5MB)
     0.0% used
    
    3170 interned Strings occupying 260168 bytes.
    

    When printing 2 . memory output after

    D:\JWF\Gitee\learn-demo\src\main\java\com\loksail\learndemo>jmap -heap 15380
    Attaching to process ID 15380, please wait...
    Debugger attached successfully.
    Server compiler detected.
    JVM version is 25.221-b11
    
    using thread-local object allocation.
    Parallel GC with 4 thread(s)
    
    Heap Configuration:
     MinHeapFreeRatio         = 0
     MaxHeapFreeRatio         = 100
     MaxHeapSize              = 4261412864 (4064.0MB)
     NewSize                  = 88604672 (84.5MB)
     MaxNewSize               = 1420296192 (1354.5MB)
     OldSize                  = 177733632 (169.5MB)
     NewRatio                 = 2
     SurvivorRatio            = 8
     MetaspaceSize            = 21807104 (20.796875MB)
     CompressedClassSpaceSize = 1073741824 (1024.0MB)
     MaxMetaspaceSize         = 17592186044415 MB
     G1HeapRegionSize         = 0 (0.0MB)
    
    Heap Usage:
    PS Young Generation
    Eden Space:
     capacity = 66584576 (63.5MB)
     used     = 17144360 (16.350135803222656MB)
     free     = 49440216 (47.149864196777344MB)
     25.748245359405757% used
    From Space:
     capacity = 11010048 (10.5MB)
     used     = 0 (0.0MB)
     free     = 11010048 (10.5MB)
     0.0% used
    To Space:
     capacity = 11010048 (10.5MB)
     used     = 0 (0.0MB)
     free     = 11010048 (10.5MB)
     0.0% used
    PS Old Generation
     capacity = 177733632 (169.5MB)
     used     = 0 (0.0MB)
     free     = 177733632 (169.5MB)
     0.0% used
    
    3171 interned Strings occupying 260232 bytes.
    

    When printing 3 . memory output after

    D:\JWF\Gitee\learn-demo\src\main\java\com\loksail\learndemo>jmap -heap 15380
    Attaching to process ID 15380, please wait...
    Debugger attached successfully.
    Server compiler detected.
    JVM version is 25.221-b11
    
    using thread-local object allocation.
    Parallel GC with 4 thread(s)
    
    Heap Configuration:
     MinHeapFreeRatio         = 0
     MaxHeapFreeRatio         = 100
     MaxHeapSize              = 4261412864 (4064.0MB)
     NewSize                  = 88604672 (84.5MB)
     MaxNewSize               = 1420296192 (1354.5MB)
     OldSize                  = 177733632 (169.5MB)
     NewRatio                 = 2
     SurvivorRatio            = 8
     MetaspaceSize            = 21807104 (20.796875MB)
     CompressedClassSpaceSize = 1073741824 (1024.0MB)
     MaxMetaspaceSize         = 17592186044415 MB
     G1HeapRegionSize         = 0 (0.0MB)
    
    Heap Usage:
    PS Young Generation
    Eden Space:
     capacity = 66584576 (63.5MB)
     used     = 1331712 (1.27001953125MB)
     free     = 65252864 (62.22998046875MB)
     2.0000307578740157% used
    From Space:
     capacity = 11010048 (10.5MB)
     used     = 0 (0.0MB)
     free     = 11010048 (10.5MB)
     0.0% used
    To Space:
     capacity = 11010048 (10.5MB)
     used     = 0 (0.0MB)
     free     = 11010048 (10.5MB)
     0.0% used
    PS Old Generation
     capacity = 177733632 (169.5MB)
     used     = 1083488 (1.033294677734375MB)
     free     = 176650144 (168.46670532226562MB)
     0.6096133791943216% used
    
    3157 interned Strings occupying 259256 bytes.
    

    Analysis

    In the output memory information, Heap Configuration is the heap setting of the program, and Heap Usage is the Heap Usage. Our main concern is the usage of Eden Space

  • After printing 1, the heap memory used is 6.350120544433594MB, and there is no object creation at this time

  • After printing 2, the heap memory used is 16.350135803222656MB. The increase of 10M is due to the creation of 10M byte array in the code

  • After printing 3, the heap memory used is 1.27001953125MB, because at this time, the byte array is set to empty, and the corresponding object space is no longer used. At this time, calling garbage collection will reclaim this part of memory, thus reducing the use of heap memory.

  • Generate heap memory dump snapshot

    jmap - dump:format=b,file = file name process number
    For example: jmap - dump:format=b,file=D://demo.hprof 13777
    

    After the heap memory is dump ed, the file is loaded with JVM, and the heap memory usage can also be analyzed

5.3.3 jconsole tools

jconsole

In the Demo program before execution, the change of heap memory can be observed obviously through jconsole. Meanwhile, jconsole can observe the relevant information of thread and CPU, and can also recycle garbage manually.

5.3.4 JVM tools

jvisualvm

This tool is similar to jconsole, but it can check the specific usage of heap memory through heap dump

Sample code

public class Demo {

    public static void main(String[] args) throws InterruptedException {
        List<Student> students = new ArrayList<>();
        for (int i = 0; i < 200; i++) {
            students.add(new Student());
        }
        Thread.sleep(100000000);
    }

    static class Student {
        private byte[] bytes = new byte[1024 * 1024];;
    }

}

The current heap memory information can be seen through the JVM, and the heap memory occupation is about 229m

After clicking to perform garbage collection, the heap memory takes up about 218m

It can be seen that the heap memory usage has not been reduced much. If the code is not analyzed, how to analyze the specific heap memory usage information?

Heap dump using JVM

From the object with the largest view size on the right, you can see that the ArrayList object occupies the largest heap memory. Click view

As you can see, the ArrayList object occupies about 200m of memory, its size is 200, the element in the collection is Student object, and its size is 1m, mainly because the byte array occupies 1m. That is to say, the list set that stores 200 Student objects takes up 200m of heap memory. Combined with code analysis, it can be seen that the ArrayList object is still in the scope of the method and is still referenced by the local variable table of the virtual machine stack, so it will not be garbage collected, so the heap memory occupation will not drop.

Welcome to pay attention to the public number, follow up articles update notice, and discuss technical problems together.

Tags: Programming Java jvm snapshot

Posted on Mon, 30 Dec 2019 21:01:39 -0800 by Barkord