Soft, weak, and virtual references to objects
StrongReference This is the most common reference in Java programs. The program creates an object and assigns the object to a reference variable that the program uses to manipulate the actual object. When an object is referenced by one or more reference variables, it is in the reachable state and cannot be collected by the system garbage collection mechanism.
2: SoftReference a SoftReference is implemented using the SoftReference class. If an object has only soft references, it may be reclaimed by the garbage collection mechanism. For objects with only soft references, when the system memory space is sufficient, it will not be reclaimed by the system, the program can also use the object; When the system memory space is insufficient, the system may reclaim it. Soft references are usually used in heap-memory sensitive programs;
WeakReference is implemented by WeakReference class. WeakReference is similar to soft reference, but the reference level of WeakReference is lower. For objects with only weak references, when the system garbage collection mechanism is running, the memory occupied by the object will be reclaimed regardless of whether the system memory is sufficient. Of course, it is not that when an object has only weak references, it is immediately reclaimed —- just as objects that have lost references must wait until the garbage collection mechanism runs;
PhantomReference A virtual reference is implemented through the PhantomReference class. A virtual reference is completely similar to no reference. The virtual reference does not have much effect on the object itself, and the object does not even feel the existence of the virtual reference. If an object has only one virtual reference, it will have much the same effect as no reference. Virtual references are used to track the garbage collection status of objects. Virtual references cannot be used alone. They must be used in conjunction with the ReferenceQueue (ReferenceQueue).
All three of the above reference classes contain a get() method to get the object they refer to;
Reference queue by Java. Lang. Ref. ReferenceQueue class representation, it is used to hold the use of recycled objects.
Soft and weak references can be used separately, but virtual references cannot be used separately. Using virtual references alone does not make much sense. The main function of the virtual reference is to track the status of the object being garbage collected. The program can know whether the object referenced by the virtual reference is reclaimed immediately by checking whether the reference queue associated with the virtual reference already contains the virtual reference.
Examples of weak references:
public class TestReference
{
public static void main(String[] args) throws Exception
{
// Create a string object
String str = new String("The Definitive Guide to Struts2");
// Create a weak reference to the "Struts2 Authoritative Guide "string
WeakReference wr = new WeakReference(str);
// Break the reference between the STR reference and the "Struts2 authoritative Guide "string
str = null;
// Fetch the object referenced by the weak reference. Since this program does not cause memory stress, it is not usual to garbage collect the objects referenced by the weak reference WR.
System.out.println(wr.get());
// Force garbage collection
System.gc();
System.runFinalization();
// Fetch the object referenced by the weak reference againSystem.out.println(wr.get()); }}/ / outputThe definitive guide to Struts2null
Copy the code
Example of a virtual reference:
public class TestPhantomReference
{
public static void main(String[] args) throws Exception
{
// Create a string object
String str = new String("The Definitive Guide to Struts2");
// Create a reference queue
ReferenceQueue rq = new ReferenceQueue();
// Create a virtual reference to the "Struts2 Authoritative Guide "string
PhantomReference pr = new PhantomReference (str , rq);
// Break the reference between the STR reference and the "Struts2 authoritative Guide "string
str = null;
// The object referenced by the virtual reference cannot be accessed through the virtual reference, so null is printed here
System.out.println(pr.get());
// Force garbage collection
System.gc();
System.runFinalization();
// Fetch the first reference in the reference queue and compare it with prSystem.out.println(rq.poll() == pr); }}/ / output
null
true
Copy the code
When the referenced object is reclaimed, the corresponding virtual reference is added to the associated reference queue, so that the program finally sees true output.
Is the object garbage?
The first thing the garbage collector does before collecting the heap is to determine which of these objects are “alive” and which are “dead.”
Reference counting algorithm
Add a reference counter to the object, incrementing the counter by 1 every time it is referenced in a place; When the reference is invalidated, the counter value is subtracted by one; An object with a counter value of 0 at any time is no longer usable. Objectively speaking, the implementation of the reference counting algorithm is simple, the determination efficiency is also very high, in most cases it is a good algorithm. However, at least in the mainstream Java Virtual Machine, reference counting algorithms are not used to manage memory, mainly because it is difficult to solve the problem of circular references between objects.
Such as:Object A refers to object B. Object B has A reference count of 1. Object B also references object A, so object A’s reference count is also 1. It is assumed that there are no more objects to reference A and B, and since the reference counts for both AB and A are 1, AB will never be garbage collected.
Accessibility analysis algorithm
In the mainstream commercial programming language (Java, C#) mainstream implementation, is called by the reachability analysis to determine whether the object is alive. The basic idea of this algorithm is to start with a series of objects called “GC Roots” and search down from these nodes. The path taken by the search is called a Reference Chain. When an object is not connected to the GC Roots by any Reference Chain, Proves that this object is not available. As shown in Figure 3-1, objects Object5, Object6 and Object7 are related to each other, but they are unreachable to GC Roots, so they will be judged as recyclable objects.In the Java language, objects that can be GC Roots include the following:
- Objects referenced in the virtual machine stack (local variable table in the stack frame);
- Objects referenced by class static properties in the method area;
- An object referenced by a constant in the area of a method;
- Objects referenced by JNI (commonly known as Native methods) in the Native method stack;
Easy to understand example: grapes, attached to the root these grapes are objects that cannot be recycled because the root refers to them. Disconnected from the root are objects that can be garbage collected
Extension – See what GC Roots objects are available?
Tool: Memory Analyzer (MAT)www.eclipse.org/mat/ Example code:
/** * Show GC Roots */
public class Demo2_2 {
public static void main(String[] args) throws InterruptedException, IOException {
List<Object> list1 = new ArrayList<>();
list1.add("a");
list1.add("b");
System.out.println(1);
System.in.read();
list1 = null;
System.out.println(2);
System.in.read();
System.out.println("end..."); }}Copy the code
For the first time, run jmap-dump :format=b,live,file=1.Bin [pid] Jmap-dump :format=b,live,file=2.Bin [pid] Parameters: -dump: indicates the running status of the heap memory. Format: indicates the format of the dumped file. B: indicates the binary formatCopy the code
Open the generated. Bin file and perform the following operations:Before garbage collection 1. Bin:2. Bin:
The finalize () method
protected void finalize(a) throws Throwable
Copy the code
Even in the reachability analysis algorithm, the unreachable objects are not “must die”. At this time, they are temporarily in the “slow xing” stage. To truly declare an object dead, it must go through at least two marking processes:
- If the object is found to have no reference chain connected with GC Roots after reacsibility analysis, it will be marked for the first time and filtered once. The filtering condition is whether it is necessary to execute finalize() method on this object. When the object does not override the Finalize () method, or when the Finalize () method has already been called by the virtual machine, the virtual machine treats both cases as “not necessary to execute”;
- If the object is determined to be necessary to execute finalize() methods, the object will be placed ina Queue called F-queue and executed later by a low-priority Finalizer thread automatically created by the virtual machine. The reason for this is that if an object executes slowly in Finalize (), or an infinite loop occurs, it will probably cause other objects in f-queue to wait forever. Finalize () method is the last chance for an object to escape the fate of death. Later, GC will mark the objects in F-queue for a second time on a small scale. If an object wants to save itself successfully in Finalize () ———– it only needs to establish a relationship with any object on the reference chain again, then it will be removed from the collection “to be recycled” in the second marking. If the object hasn’t escaped at this point, it’s basically really been reclaimed;
When The Finalize () method returns, the object disappears and the garbage collection mechanism starts to execute.
Any Java class can override the Finalize () method of the Object class to clean up the resources that the Object occupies. If there is no garbage collection before the program terminates, the Finalize () method of the lost reference object will not be called to clean up the resources.
The garbage collection mechanism is completely transparent when it calls the finalize() method of an object, and it does so only when the program decides that more additional memory is needed. For example, a lost-referenced object only occupies a small amount of memory, and the system does not incur serious memory requirements, so the garbage collection mechanism does not attempt to reclaim the resources occupied by the object, so the Finalize () method of the object will not be called;
Finalize () method has the following four characteristics:
- Never call the Finalize () method of an object actively, this method should be called by garbage collection mechanism;
- When and whether the Finalize () method is called is uncertain, so do not take finalize() method as a method that will be executed for sure;
- When the JVM executes the Finalize () method of a recoverable object, it may make the object or other objects in the system become reachable again.
- When an exception occurs when the JVM executes finalize() method, the garbage collection mechanism will not report the exception and the program continues to execute.
public class TestFinalize
{
private static TestFinalize tf = null;
public void info(a)
{
System.out.println("Finalize Method for Testing resource Cleanup");
}
public static void main(String[] args) throws Exception
{
// Create a TestFinalize object and immediately enter the deactivation state
new TestFinalize();
// Notify the system to recycle resources
System.gc();
System.runFinalization();
//Thread.sleep(2000);
tf.info();
}
public void finalize(a)
{
// Make the TF reference to the deactivated object that is trying to reclaim, i.e. the deactivated object becomes active again
tf = this; }}Copy the code
If the program only executes system.gc (); Code without performing system.runfinalization (); Code ——– Because of the uncertainty of JVM garbage collection mechanism, THE JVM often does not call the Finalize () method of recoverable objects immediately, so the FT class variable of TestFinalize may still be null, which may still cause null pointer exception.
Recovery method area
Many people think that the method area (or the permanent generation in the HotSpot virtual machine) does not have garbage collection, the Java virtual Machine specification does say that the virtual machine can not be required to implement garbage collection in the method area, and that the “cost performance” of garbage collection in the method area is generally low: In the heap, especially in the new generation, a conventional garbage collection can generally recover 70% to 90% of the space, while the permanent generation of garbage collection efficiency is much lower than this;
Permanent garbage collection has two main parts: discarded constants and useless classes. Reclaiming discarded constants is very similar to reclaiming objects in the Java heap. For example, if a String “ABC” is already in the constant pool, but there are no strings in the system that are named “ABC”, in other words, there are no strings that reference the “ABC” constants in the constant pool. There is no reference to the literal anywhere else, so if memory reclamation occurs and the “ABC” constant is cleaned out of the constant pool if necessary. The same is true for symbolic references to other classes (interfaces), methods, and fields in the constant pool; It is relatively easy to determine whether a constant is “obsolete”, while the conditions for determining whether a class is “useless” are much tougher. To be considered a “useless class”, a class must satisfy all three of the following conditions:
- All instances of the class have been reclaimed, that is, there are no instances of the class in the Java heap;
- The ClassLoader that loaded the class has been reclaimed.
- The corresponding Java.lang. Class object is not referenced anywhere, and the methods of this Class cannot be accessed anywhere through reflection;
Virtual machines can recycle useless classes that meet the above three conditions. This is just “yes”, but not the same as objects. The HotSpot virtual machine provides the -xNoClassGC parameter to control whether classes are reclaimed.
Forced garbage collection
The program cannot precisely control the timing of Java garbage collection, but it can still force the system to do it —- This force simply informs the system of garbage collection, but it is still uncertain whether the system will collect. Most of the time, programs that force garbage collection on the system will have some effect. You can force garbage collection in either of the following ways:
- Call the static gc() method of the System class: system.gc ();
- Call the GC () instance method of the Runtime object: runtime.geTruntime ().gc();
TestGc.java
public class TestGc
{
private double height;
public static void main(String[] args)
{
for (int i = 0 ; i < 4; i++)
{
newTestGc(); }}public void finalize(a)
{
System.out.println("System is cleaning up TestGc object resources..."); }}Copy the code
When compiling and running the above program, we can’t see any output. We can see that the system never calls finalize() method of TestGc object until the system exits. However, change the procedure to the following form:
public class TestGc
{
private double height;
public static void main(String[] args)
{
for (int i = 0 ; i < 4; i++)
{
new TestGc();
//System.gc();Runtime.getRuntime().gc(); }}public void finalize(a)
{
System.out.println("System is cleaning up TestGc object resources..."); }}// Output that the system is cleaning up TestGc object resources...
Copy the code
You can see that the system garbage collection mechanism has some action;
The new generation, the old generation, the permanent generation
Why do you need to generational the heap? ——————- the only reason to generational is to optimize GC performance.
If there are no generations, then all of our objects are in one place, and when WE GC we have to find out which objects are useless, so we scan all of the regions of the heap. However, many of our objects are ephemeral. If we use generations, we will put the newly created objects in one place, and when GC collects the “ephemeral” objects, it will make a lot of space.
- The New Generation: The new generation mainly stores objects that will soon be collected by GC or are not particularly large;
- Old age: Old age is for objects that are still alive or very large after being recycled several times in the program;
- Permanent generation: The method area of the JVM, also known as the permanent generation. Here are some of the virtual machine loaded class information, static variables, constants and other data. The stuff in this area is harder to recycle than the old and the new;
Garbage collection algorithm
Mark-clear algorithm
The most basic collection algorithm is the “mark-clear” algorithm. Just like its name, the algorithm is divided into two stages of “marking” and “clearing” : first, all the objects to be collected are marked out, and all the marked objects are collected uniformly after the completion of marking. Its main shortcomings are two:
- Efficiency problem: the efficiency of both marking and clearing processes is not high;
- Space problem: after the mark is cleared, a large number of discontinuous memory fragments will be produced. Too many space fragments may cause that when a large object needs to be allocated during the program running, enough continuous memory cannot be found and another garbage collection action has to be triggered in advance.
Replication algorithm
To solve the efficiency problem, a collection algorithm called “copy” has emerged, which divides the available memory into two equal sized chunks by capacity and uses only one chunk at a time. When the memory in this area runs out, the remaining objects are copied to another area, and the used space is cleaned up once again. This makes every time is to the entire half of the garbage collection, memory allocation time also do not need to consider the memory fragmentation and other complex situation, as long as the top of the heap move pointer, in order to allocate memory, simple implementation, efficient operation. However, the cost of this algorithm is to reduce the memory size to half of the original, which is too high;Commercial virtual machines now use this collection algorithm to reclaim the new generation. 98% of the objects in the new generation are dead, so there is no need to follow 1: Instead, we divide memory into a large Eden space and two smaller Survivor Spaces, using Eden and one Survivor at a time. When recollecting, the remaining objects in Eden and Survivor are copied to another Survivor space, and Eden and the previously used Survivor space are cleaned up. The default size ratio of The HotSpot virtual machine is 8:1 for Eden and Survivor, that is, the available memory space in each generation is 90% (80% + 10%) of the entire generation capacity, only 10% of the memory will be “wasted”;
Mark-collation algorithm
When the survival rate of the object is high, the copy-collection algorithm will carry out more copying operations, and the efficiency will be low. More importantly, if you do not want to waste 50% of the space, you need to have extra space for allocation guarantee, to cope with the extreme case of 100% survival of all objects in the used memory, so in the old era, this algorithm is generally not used directly;
According to the characteristics of the old era, another “mark-clean” algorithm has been proposed. The marking process is still the same as the “mark-clean” algorithm, but the next step is not to clean up the recyclable objects directly, but to make all the living objects move to one end, and then directly clean up the memory outside the end boundary.
Generational collection algorithm
The current garbage collection of commercial virtual machines uses the “generational collection” algorithm, which divides the memory into several blocks according to the lifetime of the object. Generally, the Java heap is divided into new generation and old generation, so that the most appropriate collection algorithm can be adopted according to the characteristics of each generation.
-
The New Generation (replication algorithm) : In the new generation, a large number of dead objects are found in each garbage collection. As long as a small number of surviving objects survive, the replication algorithm is selected and the collection can be completed only by paying the replication cost of a few surviving objects.
-
Old age (tag-clean or tag-clean algorithm) : In old age, the object has a high survival rate and there is no extra space to guarantee its allocation, so the tag-clear or tag-clean algorithm must be used to reclaim it;
Related VM Parameters
role | parameter |
---|---|
Initial heap size | -Xms |
Maximum heap size | The -xmx or – XX: MaxHeapSize = the size |
Cenozoic size | -xx :NewSize=size + -xx :MaxNewSize=size) |
Survival ratio (dynamic) | – XX: InitialSurvivorRatio = thewire and – XX: + UseAdaptiveSizePolicy |
Survival ratio | -XX:SurvivorRatio=ratio |
Promotion threshold | -XX:MaxTenuringThreshold=threshold |
The promotion details | -XX:+PrintTenuringDistribution |
Details on the GC | -XX:+PrintGCDetails -verbose:gc |
Before FullGC MinorGC | -XX:+ScavengeBeforeFullGC |
Garbage collector
If the collection algorithm is the methodology of memory collection, then garbage collector is the specific implementation of memory collection;
Garbage collectors fall into three categories:
serial
-
Single thread;
-
Suitable for the scene heap memory is small, suitable for personal computers;
Throughput priority
- Multithreading;
- Suitable for scenarios with large heap memory and multi-core CPU;
- Minimize STW time per unit time; The lowest percentage of garbage collection time is considered high throughput
Time use priority
- Multithreading;
- Suitable for scenarios with large heap memory and multi-core CPU;
- Minimize the time of single STW; (Multiple garbage collections may occur per unit of time)
What is STW? The stop-the-world mechanism in Java, or STW for short, suspends all other threads of The Java application (except The garbage collection helper) while The garbage collection algorithm is executing.
A global pause in Java, where all Java code stops, native code can execute, but cannot interact with the JVM; Most of these phenomena are caused by GC.Figure 3-5 shows seven collectors for different generations. If there is a wire between the two collectors, they can be used together. The area where the virtual machine is located indicates whether it belongs to a new generation collector or an old generation collector.
The difference between serial and parallel
It is easier to understand the answer from Zhihu:
Serial collector, Serial Old collector —- Serial (single thread)
Serial means Serial;
The Serial collector is the most basic and oldest collector. Serial Old is an Old version of the Serial collector.
// The specified collector can be added to the VM parameters at startup
-XX:+UseSerialGC = Serial + SerialOld
Copy the code
Conclusion:
-
Serial: Working in the new generation, using a replication algorithm
-
SerialOld: Works in the old days, using tag sorting algorithms
-
This thread does not block during garbage collection. All other threads are blocked
Exploiture —- Throughput priority (Parallel multithreading)
The word “Parallel” translates as “Parallel”;
The difference between concurrency and parallelism:The zhihu example makes sense:
Throughput is the ratio of CPU time spent running user code to total CPU consumption. Throughput = User code time/(User code time + garbage collection time). For a total of 100 minutes, garbage collection takes 1 minute, and the throughput is 99%.Conclusion:
- Parallel Scavenge is a Cenozoic collector that uses a copy algorithm
- Parallel Old: An Old version of the Parallel Scexploiture. It uses the tag-insane algorithm. This collector is available only in JDK1.6.
Concurrent Mark Sweep (CMS) collectors and ParNew collectors —- have priority response time
Concurrent translates to Concurrent;
The CMS Sweep collector is based on the “Mark Sweep” algorithm. The operation process of the CMS Sweep collector is more complicated than the previous ones. The whole process is divided into four steps, including:
- CMS Initial Mark
- CMS Concurrent Mark
- (CMS remark)
- CMS Concurrent Sweep
The initial marking and re-marking steps still require suspending the user thread. The initial marking is only to mark the objects that can be directly associated with GC Roots, which is very fast. The concurrent marking stage is the process of GC Roots Tracing, while the re-marking stage is to correct the marking records of the part of objects whose marking changes due to the continuous operation of the user program during the concurrent marking. The pause time for this phase is usually slightly longer than for the initial markup phase, but much shorter than for concurrent markup;
Since the longest concurrent marking and concurrent cleanup process threads in the entire process can both work with the user thread, the MEMORY reclamation process for the CMS collector is performed concurrently with the user thread as a whole.But CMS is far from perfect, and it has three obvious drawbacks:
- The CMS collector is very sensitive to CPU resources;
- The CMS collector is unable to process floating garbage. Concurrent Mode Failure may occur, resulting in another Full GC.
- The CMS collector is a collector based on the “mark-clean” algorithm, which can generate a large amount of space debris. If there is too much space debris, large object allocation will be a big problem. In this case, the old generation has a large space but cannot find enough continuous space to allocate the current object. Therefore, a Full GC has to be triggered in advance.
The ParNew collector is essentially a multithreaded version of the Serial collector, behaving the same except for garbage collection using multiple threads. In practice, the two collectors also share quite a bit of code, with the exception of the Serial collector, which is currently the only one that works with the CMS collector.
G1 collector
Garbage-first (G1) collector is one of the most advanced achievements in the development of collection technology. Compared with other GC collectors, G1 has the following features:
- Parallelism and Concurrency
- Generational collection
- Spatial integration
- Predictable pauses
View the garbage collector used by the current Java version
CMD enter:
java -XX:+PrintCommandLineFlags -version
Copy the code
Memory allocation and reclamation strategy
Objects are allocated first in Eden
In most cases, objects are allocated in the Cenozoic Eden zone.
Big objects go straight into the old age
Large objects are Java objects that require a large amount of contiguous memory space. The most typical large objects are long strings and arrays. Large object for the virtual machine’s memory allocation is a bad news, more bad news than have a large object is encountered a group of “the evening out” “short-lived objects”) often appear large objects can easily lead to trigger the garbage collector in advance when we’ve got a lot of memory space to obtain enough contiguous space to accommodate them;
Long-lived objects will enter the old age
The virtual machine defines an object Age counter for each object. If an object survives the Ebden birth and the first Minor GC and can be held by a Survivor, it is moved to the Survivor space and the object age is set to 1. The age of the object increases by 1 year for every Minor GC it “survives” in the Survivor field, and when its age increases to a certain level (default is 15 years), it is promoted to the middle of the old age, and the object is promoted to the age threshold of the old age, It can be set by the -xx :MaxTenuringThreshold parameter.
Dynamic object age determination
In order to better accommodate the memory conditions of different programs, the virtual machine does not always require that the age of an object reach the MaxTenuringThreshold in order to be older. If the combined size of all objects of the same age in a Survivor space is greater than the average size in a Survivor space, Objects whose age is greater than or equal to this age can enter the old age directly without waiting for the age required in MaxTenuringThreshold.
The above are notes made by learning, for the future nothing to look at, review review; Books: A deep understanding of advanced features and best practices of the Java Virtual Machine JVM ——- by Zhiming Zhou;