Part 1 of JVM_16_Garbage Collection Related Concepts_Silicon Valley

1 Understanding of System.gc()

Understanding of Systen.gc() method

  • By default, the call of System.gc() or Runtime.getRuntime().gc() will explicitly trigger Full GC, recycle the old generation and the new generation at the same time, and try to release the memory occupied by the discarded object.
  • However, the System.gc() call comes with an exemption lifespan, which does not guarantee a call to the garbage collector.
  • JVM implementers can determine the GC behavior of the JVM through the System.gc() call. Under normal circumstances, garbage collection should be performed automatically without manual triggering, otherwise it would be too troublesome . In some special cases, such as we are writing a performance benchmark, we can call System.gc() before running.

demo01Test System01()

public class SystemGCTest {
    
    
    public static void main(String[] args) {
    
    
        new SystemGCTest();
        // 提醒jvm的来及回收器执行gc,但是不确定是否马上执行
        System.gc();

        // 强制调用失去引用对象的finalize()
//        System.runFinalization();
    }

    @Override
    protected void finalize() throws Throwable {
    
    
        super.finalize();
        System.out.println("SystemGCTest 重写了finalize()");
    }
}

demo02 test recovery

public class LocalVarGC {
    
    
    /**
     * 不会回收
     */
    public void localvarGC1() {
    
    
        byte[] buffer = new byte[10 * 1024 * 1024];
        System.gc();
    }


    /**
     * 会回收
     */
    public void localvarGC2() {
    
    
        byte[] buffer = new byte[10 * 1024 * 1024];
        buffer = null;
        System.gc();
    }

    /**
     * 不会回收
     * 局部变量表中的slot未被覆盖
     *
     */
    public void localvarGC3() {
    
    
        {
    
    
            byte[] buffer = new byte[10 * 1024 * 1024];
        }
        System.gc();
    }

    /**
     * 可以回收
     * value复用了buffer的槽,可以被回收
     */
    public void localvarGC4() {
    
    
        {
    
    
            byte[] buffer = new byte[10 * 1024 * 1024];
        }
        int value = 10;
        System.gc();
    }

    /**
     * 可以回收
     */
    public void localvarGC5() {
    
    
        localvarGC1();
        System.gc();
    }

    public static void main(String[] args) {
    
    
        LocalVarGC localVarGC = new LocalVarGC();
        localVarGC.localvarGC5();
    }
}

2 Memory overflow and memory leak

Out of memory (OOM)

  • Compared with memory leaks, memory overflow is as simple as possible to understand, but similarly, memory overflow is also one of the culprits that cause program crashes.

  • Since GC has been developing, in general, unless the memory occupied by the application grows very fast, causing garbage collection to keep up with the speed of memory consumption, OOM is not easy to occur.

  • In most cases, the GC will perform garbage collection of various age groups. If it is really not enough, it will be enlarged and an exclusive Full GC operation will be performed. At this time, a large amount of memory will be recovered for continued use by the application.

  • The explanation for OutOfMemoryError in the javadoc is that there is no free memory, and the garbage collector cannot provide more memory .

  • First of all, let’s talk about the situation where there is no free memory: it means that the heap memory of the Java virtual machine is not enough. There are two reasons:

(1) The heap memory setting of the Java virtual machine is not enough.

For example: there may be a memory leak problem; it is also very likely that the size of the heap is unreasonable. For example, we have to deal with a relatively objective amount of data, but the JVM heap size is not explicitly specified or the specified value is too small. We can adjust it by parameters -Xmx, Xmx.

(2) A large number of large objects are created in the code and cannot be collected by the garbage collector for a long time (there are references)

For the old version of Oracle JDK, because the size of the permanent generation is limited, and JVMU is very inactive for permanent generation garbage collection (such as constant pool recycling, writing in types that are no longer needed), so when we continue to add new types of Sometimes, OutOfMemoryError in the permanent generation is also very common, especially when there are a large number of dynamic types generated at runtime; similar intern string caches occupy too much space, which can also cause OOM problems. The corresponding exception information will be marked and related to the permanent generation: " java.lang.OutOfMemoryError: PermGen space ".

With the introduction of the metadata area, it is no longer so embarrassing for the method to go to memory, so the corresponding OOM has changed. When OOM occurs, the exception information becomes: " java.lang.OutOfMemoryError: Metaspace ". Insufficient direct memory will also cause OOM

  • There is an implicit meaning that between throwing OutOfMemoryError, the garbage collector will usually be triggered and do its best to clean up the space.
    • For example: in the analysis of the reference mechanism, it involves that the JVM will try to recycle the object pointed to by the soft reference.
    • In the java.nio.Bits.reserveMemory() method, we can clearly see that System.gc() will be called to clean up the space.
  • Of course, not in every case the garbage collector will be triggered
    • For example, if we allocate a super large object, similar to a super large data exceeding the maximum value of the heap, the JVM can judge that garbage collection cannot solve this problem, so it directly throws OutOfMemoryError.

Memory Leak

Also known as "storage leak". Strictly speaking, only when the objects are no longer used by the program, but the GC cannot reclaim them, is it called a memory leak.

But in the actual situation, sometimes some bad timing (or negligence) will cause the life of the object to become very long or even cause OOM, which can also be called "memory leak" in a broad sense.

As far as possible, memory leaks will not cause the program to pump up immediately, but once a memory leak occurs, the available memory in the program will be gradually eroded, directly exhausting the memory, and eventually an OutOfMemory exception will occur, causing the program to crash.

Note that the storage space here is not the value of physical memory, but the size of virtual memory, which depends on the size set in the disk swap area.

image-20220904230645166

Example:

1. Singleton mode

The life cycle of a singleton is as long as that of an application, so if a reference to an external object is held in a singleton program, the external object cannot be recycled, which will lead to the prosperity of memory leaks.

2. Some resources that provide close are not closed, resulting in memory leaks

Database connection (dataSource.getConnection()), network connection (socket) and io connection must be closed manually, otherwise they cannot be recycled.

3 Stop The World

Stop the World Description

  • Stop the world, or STW for short, refers to the pause of the application during the occurrence of GC time. When a pause occurs, the entire application thread will be suspended without any response , a bit like a stuck feeling, this pause is called STW.

    • Enumerating root nodes (GC Roots) in the reachability analysis algorithm will cause all Java execution threads to stall.
      • Analysis work must be performed in a consistent snapshot
      • Consistency means that the entire execution system appears to be frozen at a certain point in time during the entire analysis
      • If the object reference relationship is still changing during the analysis process, the accuracy of the analysis results cannot be guaranteed.
  • The application thread interrupted by STW will resume after completing the GC. Frequent interruption will make the user feel like a movie stuck due to slow network speed, so we need to reduce the occurrence of STW.

  • The STW event has nothing to do with which GC is used, and all GCs have this time.

  • Even G1 cannot completely avoid the stop-the-world situation. It can only be said that the garbage collector is getting better and better, and the recycling efficiency is getting higher and higher, and the pause time is shortened as much as possible.

  • STW is automatically initiated and completed by the JVM in the background . When the user is not visible, all the normal working threads of the user are stopped.

  • Do not use System.gc() during development will cause Stop-the-world to happen.

Test STW demo

public class StopTheWorldDemo {
    
    
  public static class WorkThread extends Thread{
    
    
    List<byte[]> list = new ArrayList<byte[]>();
    @Override
    public void run() {
    
    
      try {
    
    
        while (true) {
    
    
          for (int i = 0; i < 1000; i++) {
    
    
            byte[] buffer = new byte[1024];
            list.add(buffer);
          }
          if (list.size() > 1000) {
    
    
            list.clear();
            System.gc();
          }
        }

      } catch (Exception e) {
    
    
        e.printStackTrace();
      }
    }
  }

  public static class PrintThread extends Thread {
    
    
    public final long startTime = System.currentTimeMillis();
    public int i = 0;

    @Override
    public void run() {
    
    
      try {
    
    
        while (true) {
    
    
          // 每秒打印时间信息
          long t = System.currentTimeMillis() - startTime;
          System.out.println("i = " + (i++) + ",耗时:" + t );
          Thread.sleep(1000);
        }
      } catch (Exception e) {
    
    
        e.printStackTrace();
      }
    }
  }

  public static void main(String[] args) {
    
    
    WorkThread w = new WorkThread();
    PrintThread p = new PrintThread();
    w.start();
    p.start();
  }
}

use print thread alone

i = 0,耗时:0
i = 1,耗时:1010
i = 2,耗时:2019
i = 3,耗时:3025
i = 4,耗时:4037
i = 5,耗时:5047
i = 6,耗时:6057
i = 7,耗时:7065
i = 8,耗时:8079
i = 9,耗时:9079
i = 10,耗时:10085

When the two threads are started together, the time is printed (the effect is not obvious, you should change the test)

i = 0,耗时:0
i = 1,耗时:1015
i = 2,耗时:2023
i = 3,耗时:3027
i = 4,耗时:4036
i = 5,耗时:5049
i = 6,耗时:6060
i = 7,耗时:7068
i = 8,耗时:8073
i = 9,耗时:9079
i = 10,耗时:10087

4 Parallelism and Concurrency of Garbage Collection

Concurrent

  • In the operating system, it means that several programs are running and running to completion in a period of time , and these programs are all running on the same processor.
  • Concurrency is not "simultaneous operation" in the true sense, but the CPU divides a time period into several time periods (time intervals), and then switches back and forth between these time intervals. Since the CPU processing speed is very fast, as long as the time If the interval is properly handled, the user can feel that multiple applications are running at the same time.

Parallel

  • When the system has more than one CPU, when one CPU executes one process, another CPU can execute another process, and the two processes do not seize CPU resources from each other, and can be performed at the same time, which we call parallel (Parallel).
  • In fact, the factor that determines parallelism is not the number of CPUs, but the number of cores of the CPU. For example, multiple cores of a CPU can also be parallelized.
  • It is suitable for weak interaction scenarios such as scientific computing and background processing.

Concurrency vs Parallel

Concurrency refers to multiple things happening at the same time at the same time.

Parallel means that multiple things happen at the same time at the same time.

Multiple concurrent tasks preempt resources from each other. Multiple parallel tasks do not preempt resources from each other.

Parallelism occurs only in the case of multiple CPu or a CPU with multiple cores. Otherwise, things that seem to happen at the same time are actually executed concurrently.

Concurrency and Parallelism in Garbage Collection

Concurrency and parallelism, in the context of discussing garbage collectors, they can be explained as follows:

  • Parallel (Parallel) refers to multiple garbage collection threads working in parallel, but at this time the user thread is still in a waiting state.
    • Such as ParNew, Parallel Scavenge, Parallel Old;
  • Serial
    • Compared with the concept of parallelism, single-threaded execution
    • If the memory is not enough, the program is suspended, and the JVM garbage collector is started for garbage collection. After recycling, start the thread of the program again

Concurrency and parallelism, in the context of discussing garbage collectors, can be interpreted as follows:

  • Concurrent: Refers to the simultaneous execution of the user thread and the garbage collection thread (but not necessarily in parallel, they may be executed alternately), and the garbage collection thread will not stop the running of the user program during execution.
    • The user program continues to run, while the garbage collector runs on another CPU;
    • Such as: CMS, G1

5 Safe points and safe areas

Safepoint

When the program is executed, it is not possible to stop and start GC at all places. Only at specific positions can it stop and start GC. These positions are called "safe points (Safepoint)".

The choice of Safe Point is very important. If it is too small, it may cause the GC to wait too long. If it is too frequent, it may cause runtime performance problems . The execution time of most executions is very short, usually based on " whether it has the characteristics that allow the program to execute for a long time ", such as method calls, loop jumps, and exception jumps .

How to check that all threads run to the nearest safe point and stop when GC occurs?

  • Preemptive interrupt: (currently no virtual machine is used)

    Interrupting all threads is preferred. If there are still threads that are not at the safe point, restore the thread and let the thread run to the safe point.

  • Active interrupt:

    Set an interrupt flag. When each thread runs to the Safe Point, it will actively poll this flag. If the interrupt flag is true, it will interrupt itself and suspend it.

Safe Region

The Safepoint mechanism ensures that when the program is executed, it will encounter a Safepoint that can enter the GC within a short period of time. But what about when the program "doesn't execute"? For example, the thread is in the Sleep state or Blocked state. At this time, the thread cannot respond to the JVM's interrupt request and "walks" to the safe area to interrupt and suspend. The JVM is unlikely to wait for the thread to be awakened. In this case, a safe region (Safe Region) is needed to solve it.

A safe area means that in a code segment, the reference relationship of objects will not change, and it is safe to start GC anywhere in this area. We can also regard Safe Region as an expanded SafePoint.

When actually executed:

  1. When the thread runs to the code of the Safe Region, it first marks that it has reached the Safe Region. If GC occurs during this period, the JVM will mark it as a thread in the Safe Region state;
  2. When the thread is about to leave the Safe Region, it will check whether the JVM has completed the GC. If it is completed, it will continue to run, otherwise the thread must wait until it receives a signal that it can safely leave the Safe Region;

6 Talking about references again: strong references

We hope to describe such a class of objects: when the memory space is sufficient, they can be kept in memory; if the memory space is still tight after garbage collection, these objects can be discarded.

[Interview questions that are both partial and very frequent] What is the difference between strong references, soft references, weak references, and phantom references? What is the specific usage scenario?

After the JDK1.2 version, Java has expanded the concept of references and divided references into four types: Strong Reference, Soft Reference, Weak Reference and Phantom Reference. These four citation strengths gradually weakened in turn .

Except for strong references, the other three references can be found in the java.lang.ref package. The figure below shows the types corresponding to these three reference types, and developers can use them directly in the application.

image-20220912003201532

Only the finalizer reference in the Reference subclass is visible in the package, and the other three reference types are public and can be used directly in the application

  • Strong reference : The most traditional definition of "reference" refers to the reference assignment that commonly exists in program code, that is, a reference relationship like "Object obj = new Object()". In any case, as long as the strong reference relationship still exists, the garbage collector will never recycle the referenced object.
  • Soft reference : Before the system is about to overflow the memory that can be shipped, these objects will be included in the scope of recycling for the second recycling. If there is not enough memory after this recycling, a memory overflow exception will be thrown.
  • Weak references : Objects associated with weak references can only survive until the next garbage collection. When the garbage collector works, regardless of whether there is enough memory space, the objects associated with weak references will be reclaimed.
  • Phantom reference : Whether an object has a virtual reference will not affect its lifetime at all, and it is impossible to obtain an instance of an object through a virtual reference. The only purpose of setting a phantom reference association for an object is to receive a system notification when the object is collected.

Strong Reference (Strong Reference) is not recycled

In Java programs, the most common type of reference is strong reference (over 99% of ordinary systems are strong references), which is our most common common object reference, and it is also the default reference type.

When using the new operator in the Java language to create a new object and assign it to a variable, the variable is called a strong reference to the object.

Strongly referenced objects are reachable, and the garbage collector will never reclaim the referenced object.

For an ordinary object, if there is no other reference relationship, as long as it exceeds the scope of the reference or the corresponding (strong) reference assignment is null, it can be collected as garbage. Of course, the specific recovery time depends on the garbage collection strategy. .

In contrast, objects of soft references, weak references, and phantom references are soft, weak, and virtual touchable, and can be recycled under certain conditions. Therefore, strong references are one of the main causes of Java memory leaks

  • A strong reference can directly access the target object.
  • The object pointed to by the strong reference will not be reclaimed by the system at any time. The virtual machine would rather throw an OOM exception than reclaim the object pointed to by the strong reference.
  • Strong references can lead to memory leaks

7 Talking about citations again: soft citations

Soft Reference (Soft Reference) is recycled when memory is insufficient

Soft references are used to describe objects that are useful but not required. Objects that are only associated with soft references will be included in the recovery range for the second recovery before the system is about to experience a memory overflow exception. If there is not enough memory for this recovery, a memory overflow will be thrown abnormal.

Soft references are often used to implement memory-sensitive caches. For example: the cache uses soft references again. If there is still free memory, you can temporarily reserve the cache, and clean up when the memory is insufficient, so as to ensure that colleagues who use the cache will not run out of memory.

When the garbage collector decides to reclaim a soft-reachable object at a certain point, it will clean up the soft reference and optionally store the reference in a queue (Reference Queue).

Similar to weak references, except that the Java virtual machine tries to keep the soft references alive for a longer period of time, and cleans them up as a last resort.

The java.lang.ref.SoftReference class is provided after JDK1.2 to implement soft references.

Object obj = new Object() // 声明强引用
SoftReference<Object> sf = new SoftReference<Object>(obj);
obj = null; // 取消强引用

soft reference code

public class SoftReferenceTest {
    
    
  public static void main(String[] args) {
    
    
    // 创建对象,建立软引用
//    SoftReference<User> userSoftReference = new SoftReference<>(new User((1), "test"));
    // 上面的一行代码,等价于如下的三行代码
    User user = new User(1, "test");
    SoftReference<User> userSoftReference = new SoftReference<>(user);
    user = null;

    // 从软引用中重新获得强引用对象
    System.out.println(userSoftReference.get());

    System.gc();
    System.out.println("After GC:");
    // 垃圾回收之后获得软引用中的对象
    System.out.println(userSoftReference.get());

    try {
    
    
      byte[] b = new byte[1024 * 6848 - 564 * 1024]; // 根据实际老年代的大小填写
    } catch (Throwable e) {
    
    
      e.printStackTrace();
    } finally {
    
    
      System.out.println(userSoftReference.get());
    }
  }
}
class User{
    
    
  private Integer id;
  private String name;

  public User(Integer id, String name) {
    
    
    this.id = id;
    this.name = name;
  }
}

operation result:

User@16d3586
[Full GC (System.gc()) [Tenured: 0K->569K(6848K), 0.0016977 secs] 1101K->569K(9920K), [Metaspace: 144K->144K(4480K)], 0.0017364 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
After GC:
User@16d3586
[GC (Allocation Failure) [DefNew: 110K->0K(3072K), 0.0002125 secs][Tenured: 569K->569K(6848K), 0.0006989 secs] 679K->569K(9920K), [Metaspace: 144K->144K(4480K)], 0.0009355 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Allocation Failure) [Tenured: 569K->550K(6848K), 0.0006424 secs] 569K->550K(9920K), [Metaspace: 144K->144K(4480K)], 0.0006530 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
null
Heap
 def new generation   total 3072K, used 193K [0x05000000, 0x05350000, 0x05350000)
  eden space 2752K,   7% used [0x05000000, 0x050304e0, 0x052b0000)
  from space 320K,   0% used [0x05300000, 0x05300000, 0x05350000)
  to   space 320K,   0% used [0x052b0000, 0x052b0000, 0x05300000)
 tenured generation   total 6848K, used 6834K [0x05350000, 0x05a00000, 0x05a00000)
   the space 6848K,  99% used [0x05350000, 0x059fcbd8, 0x059fcc00, 0x05a00000)
 Metaspace       used 156K, capacity 2280K, committed 2368K, reserved 4480K

Change the occupied size to: 1024 * 6848 - 570 * 1024

User@16d3586
[Full GC (System.gc()) [Tenured: 0K->548K(6848K), 0.0014516 secs] 1030K->548K(9920K), [Metaspace: 144K->144K(4480K)], 0.0014876 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
After GC:
User@16d3586
User@16d3586
Heap
 def new generation   total 3072K, used 154K [0x05200000, 0x05550000, 0x05550000)
  eden space 2752K,   5% used [0x05200000, 0x05226820, 0x054b0000)
  from space 320K,   0% used [0x054b0000, 0x054b0000, 0x05500000)
  to   space 320K,   0% used [0x05500000, 0x05500000, 0x05550000)
 tenured generation   total 6848K, used 6833K [0x05550000, 0x05c00000, 0x05c00000)
   the space 6848K,  99% used [0x05550000, 0x05bfc708, 0x05bfc800, 0x05c00000)
 Metaspace       used 156K, capacity 2280K, committed 2368K, reserved 4480K

If found, the address of the softly referenced user can be output, indicating that the softly referenced object has not been recycled.

8 Talking about references again: weak references

Weak Reference (Weak Reference) - discovery and recycling

Weak references are also used to describe those non-essential objects, and objects that are only associated with weak references can only survive until the next garbage collection occurs . During system GC, as long as weak references are found, objects that are only associated with weak applications will be recycled regardless of whether the system heap space is sufficient.

However, since the threads of the garbage collector usually have a very low priority, objects holding weak applications may not be found quickly. In this case, weakly referenced objects can exist for a longer period of time .

Weak references are the same as soft references. When constructing weak references, you can also specify a reference queue. When the weak reference object is recycled, it will be added to the specified reference queue. Through this queue, the recovery of the object can be tracked.

Soft references and weak imports are very suitable for storing dispensable cache data . If you do this, when the system memory is insufficient, the cached data will be recycled without causing memory overflow. And when the memory resources are sufficient, these cached data can exist for a long time, thereby speeding up the system.

The java.lang.ref.WeakReference class is provided after JDK1.2 to implement weak references.

Object obj = new Object(); // 生命强引用
WeakReference<Object> wr = new WeaReference<ObjecL>(obj);
obj = null; // 销毁强引用

The biggest difference between a weak reference object and a soft reference object is that when the GC is recycling, it needs to check whether the soft reference object is recycled through an algorithm, but for the weak reference object, the GC always recycles. Weakly referenced objects are easier and faster to be reclaimed by GC.

Interview question: Have you ever used WeakHashMap in your development?

Weak reference code example:

public class WeakReferenceTest {
    
    
  public static void main(String[] args) {
    
    
    // 构造了弱引用
    WeakReference<Object> weakReference = new WeakReference<>(new Object());
    // 从弱引用中重新获取对象
    System.out.println(weakReference.get());

    System.gc();
    // 不管当前内存空间足够与否,都会回收它的内存
    System.out.println("After GC:");
    System.out.println(weakReference.get());
  }
}

result:

java.lang.Object@16d3586
After GC:
null

9 Revisiting Citations: Phantom Citations

Phantom Reference - Object Recycling Tracking

Phantom Reference - Object Recycling Tracking

Also known as "ghost reference" or "phantom reference", it is the weakest of all reference types.

Whether an object has virtual references does not determine the life cycle of the object at all. If an object holds only phantom references, it is almost the same as having no references, and may be reclaimed by the garbage collector at any time.

It cannot be used alone, nor can it obtain the referenced object through phantom reference. When trying to get the object through the get() method of the phantom reference, it is always null.

The only purpose of setting a phantom association for an object is to track the garbage collection process. For example: you can receive a system notification when this object is recycled by the collector.

  • Phantom references must be used with reference queues. A phantom reference must provide a reference queue as a parameter when it is created. When the garbage collector is about to reclaim an object, if it finds that it still has a virtual reference, it will add the virtual reference to the reference queue after recycling the object to notify the application of the recycling of the object.
  • Since phantom references can track the recovery time of objects, some resource release operations can also be executed and recorded in phantom references.
  • After the JDK1.2 version, the PhatomReference class is provided to realize the phantom reference.
Object obj = new Object();
ReferenceQueue phantomQueue = new ReferenceQueue();
PhantomReference<Object> pf = new PhantomReference<Objec>(obj, phantomQueue);
obj = null;

10 Revisiting References: Finalizer References

Final Reference

  • It is used to implement the finalize() method of the object, which can also be called a finalizer reference.
  • No manual coding is required, its memory is used with reference queues.
  • At GC time, finalizer references are enqueued. The finalizer thread finds the referenced object through the finalizer reference and calls its finalize() method, and the referenced object can only be recycled during the second GC.

Guess you like

Origin blog.csdn.net/weixin_43811294/article/details/126824004