This is the fourth day of my participation in Gwen Challenge


In learning about the JVM, you will be exposed to the concept of a heap, which is a large pool of objects. A large number of object instances are managed in this object pool.

Some of the objects in the pool have very deep levels of reference. A frequently invoked interface generates objects per second at a significant rate. The relationships between objects form a vast web. While Java has always fostered an atmosphere of unlimited memory, objects can’t just grow and grow, so garbage collection is required.

How does the JVM determine which objects should be reclaimed? Which ones should be maintained?

In ancient times, there were nine ethnic groups to be executed. Refers to when some people commit serious crimes, when the emperor kills one person is not enough to calm the inner anger, will have joint liability to relatives and friends. The nine clans need to be traced first to a common ancestor and then down the chain. The same goes for garbage collection on the heap. Let’s take a closer look at how garbage collection works in the JVM.

The JVM’s GC actions are not controlled by the program and are triggered automatically when conditions are met.

When a GC occurs, the JVM can always find an ancestor that references an object. At the end of the day, if the ancestor is found to be dead, they are all removed. And the ancestors who were able to dodge the garbage collection were special: they were called GC Roots.

Tracing and searching down from GC Roots produces a Chain called the Reference Chain. When an object can’t relate to any GC Root, it is ruthlessly killed.

Obj5, Obj6, and Obj7, as shown in the figure, are destroyed when GC occurs because they cannot be associated with GC Root.

Recycling is done around GC Roots. It is also the source of many memory leaks because other references have no such rights.

So, what kind of object is GC Root? It’s not what kind of object it is, it’s where it is.

Which GC Roots are available

GC Roots is a set of must-active references. In layman’s terms, it is a potentially used object that a program can then access by direct or indirect reference.

GC Roots include:

  • In a Java thread, reference type parameters, local variables, temporary values, and so on for all methods currently being called. That is, the various references associated with our stack frame.
  • All currently loaded Java classes.
  • A Java class reference type static variable.
  • A reference type constant (String or Class) in the runtime constant pool.
  • The JVM internal data structures of some references, such as the sun. The JVM. Hotspot. The memory. The Universe.
  • Monitor objects for synchronization, such as objects whose wait() method is called.
  • JNI handles include global handles and Local handles.

These GC Roots can be divided into three general categories, and the following is easier to remember:

  • Various references to active threads.

  • Class reference to a static variable.

  • JNI references.

There are two caveats:

We are talking about active references here, not objects, which cannot be used as GC Roots. The GC process is to find all live objects and consider the rest of the space “useless”; Instead of finding all the dead objects and reclaiming the space they take up. Therefore, even if the JVM heap is very large, the tracing GC can be very fast.

Reference level

The following interview question is much more interesting: if you can find the object of Reference Chain, will it definitely survive?

In an interview, you often ask questions like “What’s the use of weak references?” Even some Java engineers who have worked for many years are half-baked about this problem and miss opportunities.

An object’s reference to another object, depending on how strong the relationship is, may break at one link in the chain.

[

This reference relationship can be further divided depending on how the chain behaves when GC occurs.

Their relationship can be divided into strong reference, soft reference, weak reference, virtual reference and so on.

Strong references

The JVM throws an OutOfMemoryError when the system runs out of memory. Such objects are not recycled even if the program terminates abnormally. This reference is one of the most common and hardline existences that can only be eliminated when the GC Roots are cut off.

This is the kind of reference you use every day in your coding. For example: new a normal object.

Object obj = new Object()
Copy the code

This approach can be problematic. If your system is accessed by a large number of users, you need to record when that User accesses the system. Unfortunately, the User object doesn’t have this field, so we decided to create an extra space for this information.

static Map<User,Long> userVisitMap = newHashMap<>(); . userVisitMap.put(user, time);Copy the code

When you run out of the User object, you expect it to be reclaimed. However, since it is referenced by userVisitMap, we have no other means to remove it. At this point, a memory leak occurs.

This can also happen on an uncapped Cache system, which can easily result in an OOM due to incorrect references and incorrect capacity.

Soft References Soft References

Soft references are used to maintain unnecessary objects. If the memory is insufficient, the system will reclaim the soft reference object. If the memory is insufficient, the system will throw an out of memory exception.

This feature is ideal for caching techniques. Such as web caching, image caching and so on.

Guava’s CacheBuilder provides Settings for soft and weak references. In this scenario, soft references are more secure than strong references.

A soft reference can be used in conjunction with a ReferenceQueue (ReferenceQueue), and if the object referenced by the soft reference is garbage collected, the Java virtual machine adds the soft reference to the ReferenceQueue associated with it.

Soft references require explicit declarations, which are implemented using generics.

/ / pseudo code
Object object = new Object();
SoftReference<Object> softRef = new SoftReference(object);
Copy the code

There is an associated JVM parameter. The lifetime of a SoftReference per MB of free heap space. The default time for this value is 1 second (1000).

-XX:SoftRefLRUPolicyMSPerMB=<N>
Copy the code

Some optimization methods circulating on the Internet, that is, set this value to 0, is actually wrong, it is easy to cause trouble, if you are interested in it, you can search for it.

This kind of partial optimization method, unless you have a good understanding of the principle, can set some special values. Values like 0, infinity, etc., are best avoided in JVM Settings.

Weak references

Weak reference objects are more useless than soft references and have a shorter life cycle.

When a JVM does garbage collection, objects associated with weak references are reclaimed regardless of whether memory is sufficient. A weak reference has a shorter life cycle, in Java, using Java. Lang. Ref. WeakReference class.

Its application scenario is similar to that of soft references and can be adopted in more memory-sensitive systems. It works like this:

/ / pseudo code
Object object = new Object();
WeakReference<Object> softRef = new WeakReference(object);
Copy the code

Phantom References

This is a figurehead reference that is not used much in real life. A virtual reference must be used in conjunction with a ReferenceQueue. If an object holds only virtual references, it can be garbage collected at any time, just as if there were no references at all.

In fact, a get for a virtual reference always returns NULL.

Object  object = new Object();
ReferenceQueue queue = new ReferenceQueue();
// A virtual reference must be associated with a reference queue
PhantomReference pr = new PhantomReference(object, queue);
Copy the code

Virtual references are mainly used to track the activity of objects being garbage collected.

When the garbage collector is about to reclaim an object and finds that it has a virtual reference, it adds the virtual reference to the reference queue associated with it before recycling the object.

If a program finds that a virtual reference has been added to the reference queue, it can take the necessary action before the memory of the referenced object is reclaimed.

The following method is an example of how to monitor GC occurrences.

private static void startMonitoring(ReferenceQueue<MyObject> referenceQueue, Reference<MyObject> ref) {
     ExecutorService ex = Executors.newSingleThreadExecutor();
     ex.execute(() -> {
         while(referenceQueue.poll()! =ref) {//don't hang forever
             if(finishFlag){
                 break;
            }
        }
         System.out.println("-- ref gc'ed --");

    });
    ex.shutdown();
}
Copy the code

There is a more elegant implementation based on virtual references, and that is the New Cleaner added after Java 9, which replaces the Finalizer method of the Object class.

Typical OOM Scenario

The full name Of OOM is Out Of Memory. You can look at the color part of the memory partition diagram.

You can see that OOM overflow is possible in all areas except the application counter. But the most common is in the heap.

So what exactly causes OOM? There are several reasons:

  • The memory capacity is too small and needs to be expanded or the heap size needs to be adjusted.

  • Incorrect reference, memory leak. The relationship with GC Roots was not cut off in time. For example, threads in a thread pool forget to clean up the contents of a ThreadLocal in case of reuse.

  • The range of the interface is not verified, and the external parameters are out of the range. Procedure For example, the number of items per page in a database query.

  • Unlimited use of out-of-heap memory. In a more serious case, the operating system may run out of memory.

A typical memory leak scenario occurs when an object does not free its reference in time. For example, a local variable is referenced by an external static collection.

When writing regular code, be aware of this and never reference objects around for convenience. Even if references are made, manually clean them up when appropriate.

summary

The technical name for GC Roots is accessibility analysis. In addition, there is a method called reference counting, which is often used to determine the survival of objects.

Because of the vulnerability of loop dependency, none of the major JVMS implement GC using reference counting, so you can get a general idea. Reference counting maintains a counter counter in the head of the object that is referenced by +1 at a time, and the reference invalidation count is -1. When the counter is 0, it is considered invalid. You can forget about reference counting now.

This article details what GC Roots includes. HostSpot adopts the tracing method for GC. The speed of memory collection is related to the number of objects in the living state.

This section covers a lot of ground, so if you are asked in an interview, you can use the vernacular version of the introduction and give further examples.