Java GC learning practice

Recently, I often go to the customer's site. If there is a problem on the site, I will send it to the company's leaders (I really don't understand it. I will take advantage of the Expo to have a rest and make up for it)

Refer to "deep understanding of Java virtual machine"

Directory (Java GC learning practice)

  1. On foundation
  • 1.1 runtime data area (Java 1.8)
  • 1.2 garbage collection algorithm
  • 1.3 garbage collector
  1. Parse GC log
  2. JVM monitoring tool [see Java GC learning practice (2))
  3. Linux monitoring [see Java GC learning practice (2))

I. Foundation

1. Runtime data area

1.1 program counter

  • (Program Counter Register) [thread isolation]
  • It can be simply understood as the bytecode line number indicator executed by the current thread;
  • If java method is used, the counter record points to the instruction address of byte code of virtual machine; if native method is used, the counter value is undefined;
  • [abnormal correlation] the only area where OOM is not specified.

1.2 virtual machine stack

  • (VM Stack) [thread isolation]
  • It describes the memory model of Java method execution: [emphasis] each method execution process will create a Stack Frame to store local variable table, operand stack, dynamic link, method exit and other information. Method calls to the end of execution, corresponding to a Stack Frame in the virtual machine stack stack stack to stack out of the process;
  • [exception correlation] if the stack depth requested by a thread is greater than the depth allowed by the virtual machine, a StackOverflowError exception will be thrown. Method will create a stack frame every time it is called, and then the stack frame will be pressed. You can't press the stack indefinitely;
  • [exception related] most virtual machine stacks can be dynamically expanded. If sufficient memory cannot be applied during expansion, OOM will occur.
  • For code example, see code01.StackOverflowError at the end of the article

1.3 local method stack

  • (Native Method Stack) [thread isolation]
  • The difference between virtual machine stack and virtual machine stack is that the virtual machine stack performs java method (bytecode) service, while the non method stack is native method service;
  • [exception correlation] StackOverflowError, OOM.

1.4 piles

  • (Heap) [thread sharing]
  • GC heap is the main area of garbage collector management;
  • After java1.8 [young generation, old age].
  • For code example, see code02.OOM-heap at the end of the article

1.5 metadata area

  • (Metaspace) [thread sharing]
  • jvm config example: -XX:MetaspaceSize=8m -XX:MaxMetaspaceSize=50m
  • Metadata area replaces permanent generation, which is essentially the implementation of method area, used to store class information, constants, static variables and JIT compiled code loaded by virtual machine.
  • For code example, see code03.oom-metasface at the end of the article

2. Garbage collection algorithm

  • Is the object in? Reference counting algorithm and reachability analysis algorithm
  • Mark clear algorithm (mark first, then clear, after clearing, the space is discontinuous, resulting in a large number of memory fragments)
  • Replication algorithm
    • Young generation: Eden: Survivor = 1:8, 10% of memory will be "idle";
    • After each GC, the surviving objects will be placed in the remaining 10% of memory, that is to survive;
    • Of course, if the remaining 10% of memory is not enough, we need to rely on the old age for allocation guarantee.
  • Mark organize algorithm
    • If the survival rate of objects is high, the replication algorithm is not easy to use;
    • After the mark clear algorithm, all the surviving objects are moved to one end, and then the memory outside the boundary is cleaned up.
  • Generational collection algorithm
    • Typical is divided into the new generation and the old generation
    • New generation, low survival rate, use replication algorithm
    • In the old days, the survival rate was high and there was no extra space for guarantee, so the "mark clear" or "mark organize" algorithm was used

3. Garbage collector

3.1 new generation collector Serial

  • [single thread] has a long history, new generation collector, replication algorithm;
  • When GC, STW is required until GC is finished (your mother is cleaning, and you throw paper scraps at the same time, so STW is required, and you have to sit still);
  • The default new generation collector in Client mode (simple and efficient compared with other single thread collectors).

3.2 new generation collector ParNew

  • [parallel multithreading] new generation collector, replication algorithm, multithreaded version of Serial collector;
  • Single CPU can't be better than Serial, and even double CPU can't surpass Serial 100%;
  • In Server mode, the new generation collector is preferred. The important reason is that it can work with CMS (real concurrent collector).

3.3 new generation collector Parallel Scavenge

  • [Throughput] Throughput priority
  • [parallel multithreading] new generation collector, replication algorithm;
  • There are different concerns. The goal is to control the Throughput. Other concerns are to shorten the GC STW time as much as possible;
  • Throughput = run user code time / (run user code time + GC time)

3.4 Serial Old

  • [single thread] old generation collector, mark organize algorithm;
  • Virtual machine in Client mode of main user; virtual machine in Server mode, 1. JDK 1.6 used with PS before; 2. Back plan of CMC collector.

3.5 Parallel Old

  • [Throughput] Throughput priority
  • [parallel multithreading] old generation collector, mark organize algorithm;
  • Before jdk1.6, if PS was selected, CMS could not be selected, only Serial Old could be selected;
  • Throughput first combination.

3.6 old age collector CMS

  • [concurrent multithreading] the older generation collector, based on mark clear (initial & concurrent & retag, concurrent clear);
  • There are different concerns. The goal is to control the Throughput. Other concerns are to shorten the GC STW time as much as possible;
  • Concurrent low pause; disadvantages: CPU resources are very sensitive, floating garbage cannot be handled, and multi fragments can be removed based on tags.

3.7 G1 collector

  • It's a little more. Hold on...

II. Parsing GC log

1. Complete GC log

2019-11-04T16:05:43.267+0800: 147.981: [GC (Allocation Failure) [PSYoungGen: 150496K->5938K(147456K)] 198958K->57548K(202752K), 0.0304547 secs] [Times: user=0.05 sys=0.00, real=0.03 secs]
Heap after GC invocations=39 (full 3):
PSYoungGen      total 147456K, used 5938K [0x00000000f6700000, 0x0000000100000000, 0x0000000100000000)
eden space 141312K, 0% used [0x00000000f6700000,0x00000000f6700000,0x00000000ff100000)
from space 6144K, 96% used [0x00000000ffa00000,0x00000000fffcc8f8,0x0000000100000000)
to   space 7680K, 0% used [0x00000000ff100000,0x00000000ff100000,0x00000000ff880000)
ParOldGen       total 55296K, used 51610K [0x00000000e3400000, 0x00000000e6a00000, 0x00000000f6700000)
object space 55296K, 93% used [0x00000000e3400000,0x00000000e6666870,0x00000000e6a00000)
Metaspace       used 80445K, capacity 83414K, committed 83584K, reserved 1122304K
class space    used 10018K, capacity 10577K, committed 10624K, reserved 1048576K
}
{Heap before GC invocations=40 (full 4):
PSYoungGen      total 147456K, used 5938K [0x00000000f6700000, 0x0000000100000000, 0x0000000100000000)
eden space 141312K, 0% used [0x00000000f6700000,0x00000000f6700000,0x00000000ff100000)
from space 6144K, 96% used [0x00000000ffa00000,0x00000000fffcc8f8,0x0000000100000000)
to   space 7680K, 0% used [0x00000000ff100000,0x00000000ff100000,0x00000000ff880000)
ParOldGen       total 55296K, used 51610K [0x00000000e3400000, 0x00000000e6a00000, 0x00000000f6700000)
object space 55296K, 93% used [0x00000000e3400000,0x00000000e6666870,0x00000000e6a00000)
Metaspace       used 80445K, capacity 83414K, committed 83584K, reserved 1122304K
class space    used 10018K, capacity 10577K, committed 10624K, reserved 1048576K

=====================Dividing line==========================
2019-11-04T16:05:43.298+0800: 148.011: [Full GC (Ergonomics) [PSYoungGen: 5938K->0K(147456K)] [ParOldGen: 51610K->48605K(83968K)] 57548K->48605K(231424K), [Metaspace: 80445K->80445K(1122304K)], 0.3256949 secs] [Times: user=0.55 sys=0.00, real=0.32 secs]
=====================. . . ==========================

2. Extract main contents

2019-11-04T16:05:43.267+0800: 147.981: [GC (Allocation Failure) [PSYoungGen: 150496K->5938K(147456K)] 198958K->57548K(202752K), 0.0304547 secs] [Times: user=0.05 sys=0.00, real=0.03 secs]
2019-11-04T16:05:43.298+0800: 148.011: [Full GC (Ergonomics) [PSYoungGen: 5938K->0K(147456K)] [ParOldGen: 51610K->48605K(83968K)] 57548K->48605K(231424K), [Metaspace: 80445K->80445K(1122304K)], 0.3256949 secs] [Times: user=0.55 sys=0.00, real=0.32 secs]

3. Analysis log

  • 147.981 and 148.011: seconds since the JVM was started

  • GC and Full GC: indicates the type of garbage collection pause. Note: it is not used to distinguish the new generation from the old generation

    • GC (Allocation Failure) Allocation Failure refers to allocation failure, that is, insufficient space;
    • Full GC (Ergonomics) Ergonomics can be understood as adaptive, which means that the balance between STW time and throughput can be adjusted automatically;
    • A GC triggered by a Full GC (System) call to System.gc().
  • [PSYoungGen: 150496K->5938K(147456K)]

    • PSYoungGen, PS for Parallel Scavenge collector
    • DefNew (Default New Generation), i.e. using the Serial collector
  • [ParOldGen: 51610K->48605K(83968K)]

    • ParOldGen, ParOld means Parallel Old collector, throughput first
  • [XXXXXX: 150496K->5938K(147456K)]

    • 150496k - > 5938k (147456k) used capacity of this memory area before GC - > used capacity of this memory area after GC (total capacity of this memory area)
  • 198958k - > 57548k (202752k) Java heap used capacity before GC - > java heap used capacity after GC (total Java heap capacity)

  • 0.0304547 total secs GC time (SECs seconds)

  • [Times: user=0.05 sys=0.00, real=0.03 secs] user CPU time, kernel CPU time and wall clock time

    • Difference between CPU time and wall clock time: wall clock time includes various non operation waiting time, such as waiting for disk and thread blocking;
    • When there are multiple CPUs or cores, multiple threads will stack these CPU times, so it is completely normal for user or sys to exceed real.

Code example

code01.StackOverflowError

public class StackOverflowMain {

    public static void main(String[] args) {
        // will throw java.lang.StackOverflowError
        Test test = new Test();
        try {
            test.increment();
        } catch (StackOverflowError e) {
            System.out.println("sof error, this count is " + test.count);
            e.printStackTrace();
        }
    }

    static class Test {
        private static int count;
        void increment() {
            count++;
            increment();
        }
    }

}

code02.OOM-heap

public class OOMMain {

    private static String STR = "string";

    /**
     * -verbose:gc -XX:+HeapDumpOnOutOfMemoryError
     * -XX:HeapDumpPath=C:\\Users\\User\\Desktop\\gc
     * will throw oom by Java heap space
     */
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        while (true) {
            list.add(STR += STR);
        }
    }

}

code03.OOM-metaspace

public class OOMByCglibMain {

    /**
     * -verbose:gc -XX:+HeapDumpOnOutOfMemoryError
     * -XX:HeapDumpPath=C:\\Users\\User\\Desktop\\gc
     * -XX:MetaspaceSize=9m -XX:MaxMetaspaceSize=9m
     * will throw oom by Metaspace
     */
    public static void main(String[] args) {
        ClassLoadingMXBean loadingBean = ManagementFactory.getClassLoadingMXBean();
        while (true) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(OOMByCglibMain.class);
            enhancer.setCallbackTypes(new Class[]{Dispatcher.class, MethodInterceptor.class});
            enhancer.setCallbackFilter(new CallbackFilter() {
                @Override
                public int accept(Method method) {
                    return 1;
                }

                @Override
                public boolean equals(Object obj) {
                    return super.equals(obj);
                }
            });

            Class clazz = enhancer.createClass();
            System.out.println(clazz.getName());
            //Display quantity information (total number of loaded types, number of currently valid types, number of unloaded types)
            System.out.println("total: " + loadingBean.getTotalLoadedClassCount());
            System.out.println("active: " + loadingBean.getLoadedClassCount());
            System.out.println("unloaded: " + loadingBean.getUnloadedClassCount());
        }

    }

}

Tags: Programming Java jvm REST Linux

Posted on Mon, 04 Nov 2019 20:09:16 -0500 by Frango