First, the MEMORY structure of the JVM consists of five regions: program counters, virtual machine stack, local method stack, method area, and heap area. Among them, the program counter, virtual machine stack and local method stack are started and destroyed with the thread, so the memory allocation and reclamation of these areas are deterministic, and there is no need to consider the reclamation problem too much. Unlike the Java heap and method areas, where the allocation and collection of memory is dynamic, the formal garbage collection needs to be concerned about the part.

Garbage collection Before the heap is collected, it is necessary to determine which objects in the region can be collected and which objects cannot be collected for the time being. The following algorithm is used to negotiate the survival of broken objects.

An algorithm that determines whether an object is alive

1. Reference counting algorithm

Reference counting algorithm: Each object instance in the heap has a reference counter, when an object is created, it will be the object instance is assigned to a variable, the reference count is set to 1, when any other variable assigned to the object reference count + 1, when an object instance of a reference than the life cycle or assigned to a new value, the reference count minus 1.

Any instance of an object with a reference counter of 0 can be garbage collected. When an object instance is garbage collected, the reference counter for all object instances it references decreases by 1.

Advantages: Reference counters can be quickly executed without long interruptions to programs

Disadvantages: Circular references cannot be detected. If object A has A reference to object B, and object B has A reference to object A, their reference count will never be zero

2. Accessibility analysis algorithm

Accessibility algorithm: all the reference relationship as a diagram, starting from a node GC Root, find the corresponding reference node, continue to look for this node after find out the reference node, when all the reference node seeking to end, the rest of the node is considered not cited, or nodes, useless useless nodes was judged to be recycled.

The following types of GC Root are available in Java:

  1. Reference objects in the virtual machine stack
  2. The object referenced by the class static property in the method area
  3. The object referenced by the constant in the method area
  4. Objects referenced in the local method stack

Reference types in Java can be seen in this article Java control class reference types, rational use of memory

Common garbage collection algorithms

1. Mark-clear algorithm

The mark-clean algorithm uses GC Roots to scan and mark the surviving objects. After marking, unmarked objects in the whole space are scanned for garbage collection

This algorithm is relatively easy to implement, but it causes memory fragmentation

2. Mark-copy algorithm

Replication algorithm is proposed to solve the defect of mark-clear algorithm.

It divides memory into two equally sized pieces, using only one of them at a time. When fast A runs out, the surviving objects are copied onto block B, and block A is cleaned up at once

Although this algorithm is simple to implement, runs efficiently and does not generate memory fragmentation, it comes at a high price for memory space usage, because the available space is reduced by half. Obviously, the efficiency of the replication algorithm is closely related to the number of viable objects. If there are many viable objects, the efficiency will be greatly reduced

3. Mark-tidy algorithm

This algorithm is proposed to solve the defect of replication algorithm and make full use of memory space.

This algorithm is the same as the mark-clean algorithm, but after marking, instead of cleaning up the recoverable objects directly, the living objects are moved to one end and then the memory beyond the boundary is cleaned up.

4. Generational collection algorithm

The generational collection algorithm is currently used by most JVM garbage collectors. The core idea is to divide memory into several different regions according to the life cycle of the object.

It can be divided into young generation, old generation and permanent generation. Then appropriate collection algorithms are adopted according to different regions.

Java typically divides the heap into young and old generations and methods into permanent generations.

The following is a brief description of the different age generations

Young generation: This is where newly created objects are stored. Because the young generation is frequently GC cleaned, the JVM uses a mark-copy algorithm in the young generation, marking the surviving instances, then purging the useless instances, and copying the surviving instances to different generations based on age (the age of each instance is increased by one after GC).

Old age: Old age is an object that has survived N of this garbage culprit, where N is determined by the JVM’s parameters. This memory area is generally larger than the young generation. GC also occurs less often than in the younger generation.

Permanent generation: Used to store static files, such as Java classes and methods. Is the method area.

The main contents of the method area are: discarded constants and useless classes. The reachability of references can be judged for discarded constants and useless classes, but the following three conditions should be met for useless classes:

  1. All instances of this class have been reclaimed
  2. The ClassLoader that loaded the class has been reclaimed
  3. The java.lang.Class object corresponding to this Class is not referenced anywhere, and the methods of this Class cannot be accessed anywhere through reflection

When does GC trigger

The GC runs in the lowest priority thread and is typically called when the application is idle. It is called when memory is low

Because objects are processed in generations, garbage collection regions and times are different. There are two types of GC:

1.Scavenge GC

The Scavenge GC is typically triggered when a new object is created and the younger generation fails to claim space. This type of GC does not affect older generations. Because most objects are started in the young generation, and the young generation memory is not allocated very heavily, GC of all the young generations will occur frequently. So here we have to use a fast, efficient algorithm to make it empty as quickly as possible.

If the memory allocation is not satisfied after one GC, the JVM will perform a second GC. If it is still not satisfied, an “out of memory” error will be reported and the Java application will stop

2.Full GC

The entire memory is collated, including the young, old, and permanent generations, so Full GC is slower than the Scavenge avenge, so try to minimize the amount of Full GC you do. The following can cause Full GC:

  1. The old years are full
  2. The permanent generation is written full
  3. System.gc() is called on display
  4. The allocation strategy for each domain of the heap has changed dynamically since the last GC.

With that said, here are some tips on how to reduce the overhead of GC in your application:

  1. Do not explicitly call system.gc (). This function recommends that the JVM do GC, and while it is only a suggestion, GC is triggered in most cases, increasing the number of intermittent pauses that can have a significant impact on system performance
  2. Minimize the use of temporary objects. Reduce the chance of Scavenge GC execution
  3. It is best to explicitly set the object to NULL when it is not in use. Null objects that are not in use are easier for the GC collector to determine, thus increasing the efficiency of GC
  4. Minimize static object variables. Static variables are global variables and are not to be blamed by GC.
  5. Don’t use wrapper classes if you can have basic types. The base type variable stack uses much less memory resources than the corresponding wrapper class
  6. Use StringBuffer instead of the String class to accumulate strings. Because when a String is added to the heap, a new String is created, and a StringBuffer is a variable length that is amplified without creating intermediate objects
  7. Spread out the time an object is created or deleted. Faced with the sudden need for a lot of memory to create new objects, especially large objects, in a short amount of time, the JVM can only perform GC to reclaim memory or consolidate memory fragments, increasing the frequency of GC. The same goes for deleting objects centrally. It makes a lot of junk objects suddenly appear, and free space inevitably decreases, greatly increasing the chances of forcing the main GC the next time a new object is created.