There are four reference types in Java/Android, namely:
Strong reference - Strong reference
Soft Reference - Soft Reference
Weak Reference - Weak Reference
Phantom Reference - Virtual Quotation
Different reference types have different characteristics and also correspond to different usage scenarios.
1.Strong reference - Strong reference
The most common type of reference in actual encoding. Common forms such as: A a = new A(); etc. The strong reference itself is stored in the stack memory, and it stores the address to the object in memory. Generally, when there is no longer any strong reference to the object in memory pointing to it, the garbage collection machine starts to consider the garbage collection that might be done on this memory. If encoding: a = null, at this time, the address that was just allocated in the heap and created has no other references. When the system performs garbage collection, the heap memory will be garbage collected.
SoftReference, WeakReference, and PhantomReference are all subclasses of the class java.lang.ref.Reference. Reference, as an abstract base class, defines the basic operations of its subclass objects. Reference subclasses all have the following characteristics:
1. The Reference subclass cannot be created directly without parameterization. It must at least use the strong reference object as the construction parameter to create their respective subclass objects;
2. Because the object is created in 1 with the strong reference object as the construction parameter, the objects in the heap memory pointed to by the originally strong reference will no longer be directly related to the strong reference itself, but will also have a certain connection with the reference of the subclass object of Reference. And this connection may affect the garbage collection of the object.
According to the different influence characteristics of different subclass objects on garbage collection of their indicator objects (strong references to objects in heap memory pointed to), three subclasses are formed, namely SoftReference, WeakReference and PhantomReference.
2.Soft Reference - Soft Reference
The general use form of soft reference is as follows:
A a = new A();
SoftReference<A> srA = new SoftReference<A>(a);
Through the strong reference of the object as a parameter, a SoftReference object is created and the wrA in the stack memory points to this object.
At this time, the following encoding is performed: a = null. What impact does it have on the garbage collection of the object A originally pointed to by a?
Let’s take a look at the output results of the following program:
import java.lang.ref.SoftReference;public class ReferenceTest { public static void main(String[] args) { A a = new A(); SoftReference<A> srA = new SoftReference<A>(a); a = null; if (srA.get() == null) { System.out.println("a object enters the garbage collection process"); } else { System.out.println("a object has not been recycled yet" + srA.get()); } // Garbage collection System.gc(); if (srA.get() == null) { System.out.println("a object enters garbage collection process"); } else { System.out.println("a object has not been recycled yet" + srA.get()); } }}class A {} ##The output result is:
1 a object has not been recycled A@4807ccf62 a object has not been recycled A@4807ccf6
When a = null, the A object in the heap memory will no longer have any strong references to it, but there is a fashionable object referenced by srA pointing to the A object. When the srA.get() method is called for the first time to return this indicator object, since the garbage collector is likely to have not yet performed garbage collection, get() has a result at this time, which is easy to understand. When the program executes System.gc(); forcing garbage collection, through srA.get(), it is found that the indicated A object can still be obtained, indicating that the A object has not been garbage collected. So, when will the objects indicated by the soft reference begin to be garbage collected? The following two conditions need to be met:
1. When the object it indicates does not have any strong reference object pointing to it;
2. When the virtual machine has insufficient memory.
Therefore, SoftReference extends the time it indicates that the object occupies the heap memory until the virtual machine has insufficient memory. The garbage collector does not recycle this heap memory space.
3.Weak Reference - Weak Reference
Similarly, the general use form of soft reference is as follows:
A a = new A();
WeakReference<A> wrA = new WeakReference<A>(a);
When there is no strong reference pointing to this object, what are its garbage collection characteristics?
import java.lang.ref.WeakReference;public class ReferenceTest { public static void main(String[] args) { A a = new A(); WeakReference<A> wrA = new WeakReference<A>(a); a = null; if (wrA.get() == null) { System.out.println("a object enters the garbage collection process"); } else { System.out.println("a object has not been recycled yet" + wrA.get()); } // Garbage collection System.gc(); if (wrA.get() == null) { System.out.println("a object enters garbage collection process"); } else { System.out.println("a object has not been recycled yet" + wrA.get()); } }}class A {} ##The output result is:
A object has not been recycled yet A@52e5376aa object enters the garbage collection process
The first result output is explained as above. After garbage collection, wrA.get() will return null, indicating that it indicates that the object has entered the garbage collection process. Therefore, the characteristics of weak citations are summarized as:
WeakReference does not change the garbage collection timing of the original strong reference object. Once it indicates that the object does not have any strong reference object, the object enters the normal garbage collection process.
So, based on this characteristic, there is a question: What is the significance of WeakReference?
Its main usage scenarios are: There are currently strong references pointing to strong reference objects. At this time, due to business needs, it is necessary to increase references to this object, and at the same time, it is not intended to change the garbage collection timing of this reference. At this time, WeakReference just meets the needs and is commonly found in some scenarios with life cycles.
The following is a scenario for the use of WeakReference in Android - combining static inner classes and WeakReference to solve the possible Handler memory leak problem in the Activity.
In the Activity, we need to create a new thread to obtain data and use handler - sendMessage method. Here is the general code for this process:
public class MainActivity extends Activity { //... private int page; private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { if (msg.what == 1) { //... page++; } else { //... } }; }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //... new Thread(new Runnable() { @Override public void run() { //.. Message msg = Message.obtain(); msg.what = 1; //msg.obj = xx; handler.sendMessage(msg); } }).start(); //... }}Run Link in Eclispe, you will see a warning message: This Handler class should be static or leaks might occur...Click to view this information, which describes the problem in the details and provides a suggestive solution.
Issue: Ensures that Handler classes do not hold on to a reference to an outer classId: HandlerLeakSince this Handler is declared as an inner class, it may prevent the outer class from being garbage collected. If the Handler is using a Looper or MessageQueue for a thread other than the main thread, then there is no issue. If the Handler is using the Looper or MessageQueue of the main thread, you need to fix your Handler declaration, as follows: Declare the Handler as a static class;In the outer class, instantiate a WeakReference to the outer class and pass this object to your Handler when you instantiate the Handler; Make all references to members of the outer class using the WeakReference object.
The general meaning is that it is recommended to define the Handler as an internal static class, and define a reference to WeakReference in this static inner class, due to indicating the external Activity object.
Problem analysis:
Activity has its own life cycle. During the running process of newly opened threads in the Activity, the user may press the Back key or the system is insufficient memory, etc. to recycle this Activity. Because the newly launched threads in the Activity will not follow the cycle of the Activity itself, that is, when the Activity executes onDestroy, due to the existence of threads and Handler's HandleMessage, the system originally hopes to perform memory recovery of this Activity cannot be implemented, because the non-static internal class implicitly holds references to external classes, resulting in possible memory leakage problems.
Therefore, when using Handler in Activity, on the one hand, it needs to be defined as a static inner class form, so that it can be decoupled from the external class and no longer hold references to the external class. At the same time, since the handlerMessage in the Handler generally needs to access or modify the properties of the Activity, at this time, the WeakReference pointing to this Activity needs to be defined inside the Handler so that it will not affect the memory recovery of the Activity. At the same time, the properties of the Activity can be accessed under normal circumstances.
The official Google recommendations are:
public class MainActivity extends Activity { //... private int page; private MyHandler mMyHandler = new MyHandler(this); private static class MyHandler extends Handler { private WeakReference<MainActivity> wrActivity; public MyHandler(MainActivity activity) { this.wrActivity = new WeakReference<MainActivity>(activity); } @Override public void handleMessage(Message msg) { if (wrActivity.get() == null) { return; } MainActivity mActivity = wrActivity.get(); if (msg.what == 1) { //... mActivity.page++; } else { //... } } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //... new Thread(new Runnable() { @Override public void run() { //.. Message msg = Message.obtain(); msg.what = 1; //msg.obj = xx; mMyHandler.sendMessage(msg); } }).start(); //... }}For SoftReference and WeakReference, there is also a constructor parameter ReferenceQueue<T>, and when the object indicated by SoftReference or WeakReference is indeed garbage collected, its reference will be placed in the ReferenceQueue. Note that as above, when the get() method of SoftReference or WeakReference returns null, it only indicates that the object it indicates has entered the garbage collection process, and the object may not have been garbage collected at this time. Only after confirming that it has been garbage collected, if the ReferenceQueue is, its reference will be placed in the ReferenceQueue.
See an example below:
public class ReferenceTest { public static void main(String[] args) { A a = new A(); WeakReference<A> wrA = new WeakReference<A>(a); a = null; if (wrA.get() == null) { System.out.println("a object enters the garbage collection process"); } else { System.out.println("a object has not been recycled yet" + wrA.get()); } // Garbage collection System.gc(); if (wrA.get() == null) { System.out.println("a object enters the garbage collection process"); } else { System.out.println("a object has not been recycled yet" + wrA.get()); } }}class A { @Override protected void finalize() throws Throwable { super.finalize(); System.out.println("in A finalize"); }} ##The output result is:
1 a object has not been recycled A@46993aaa2 a object has been recycled 3 in A finalize
This also verifies the statement "entering the garbage collection process" mentioned above. Let’s look at a piece of code in combination with ReferenceQueue:
public class ReferenceTest { public static void main(String[] args) { A a = new A(); ReferenceQueue<A> rq = new ReferenceQueue<A>(); WeakReference<A> wrA = new WeakReference<A>(a, rq); a = null; if (wrA.get() == null) { System.out.println("a object enters the garbage collection process"); } else { System.out.println("a object has not been recycled yet" + wrA.get()); } System.out.println("rq item:" + rq.poll()); // Garbage collection System.gc(); if (wrA.get() == null) { System.out.println("a object enters the garbage collection process"); } else { System.out.println("a object has not been recycled yet" + wrA.get()); } /* try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } */ System.out.println("rq item:" + rq.poll()); }}class A { @Override protected void finalize() throws Throwable { super.finalize(); System.out.println("in A finalize"); }} ##The output result is:
a object has not been recycled yet A@302b2c81rq item:nulla object enters the garbage collection process rq item:nullin A finalize
Thus, it is verified that "SoftReference or WeakReference references that enter only the garbage collection process have not been added to the ReferenceQueue".
public class ReferenceTest { public static void main(String[] args) { A a = new A(); ReferenceQueue<A> rq = new ReferenceQueue<A>(); WeakReference<A> wrA = new WeakReference<A>(a, rq); a = null; if (wrA.get() == null) { System.out.println("a object enters the garbage collection process"); } else { System.out.println("a object has not been recycled yet" + wrA.get()); } System.out.println("rq item:" + rq.poll()); // Garbage collection System.gc(); if (wrA.get() == null) { System.out.println("a object enters the garbage collection process"); } else { System.out.println("a object has not been recycled yet" + wrA.get()); } try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("rq item:" + rq.poll()); }}class A { @Override protected void finalize() throws Throwable { super.finalize(); System.out.println("in A finalize"); }} ##The output result is:
a object has not been recycled yet A@6276e1dbrq item:nulla object enters the garbage collection process in A finalizerq item:java.lang.ref.WeakReference@645064f
This confirms the above statement.
4.PhantomReference
Compared with SoftReference or WeakReference, the main differences in PhantomReference are reflected in the following points:
1. PhantomReference has only one constructor PhantomReference(T reference, ReferenceQueue<? super T> q), so PhantomReference must be used in combination with ReferenceQueue;
2. Regardless of whether there is a strong reference to the indicator object pointing to PhantomReference, the get() method of PhantomReference returns the result null.
public class ReferenceTest { public static void main(String[] args) { A a = new A(); ReferenceQueue<A> rq = new ReferenceQueue<A>(); PhantomReference<A> prA = new PhantomReference<A>(a, rq); System.out.println("prA.get():" + prA.get()); a = null; System.gc(); try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("rq item:" + rq.poll()); }}class A {} ##The output result is:
prA.get():nullrq item:java.lang.ref.PhantomReference@1da12fc0
The Thread.sleep(1); in the code functions the same as in the above example, and both ensure that the garbage collection thread can execute. Otherwise, virtual references to the indicator object that enter the garbage collection process without being actually garbage collected will not be added to the PhantomReference.
Like WeakReference, PhantomReference does not change the garbage collection timing of its indicating object. It can be concluded that the function of ReferenceQueue is mainly used to listen to the SoftReference/WeakReference/PhantomReference indicating whether the object has been garbage collected.
The above is the full content of the comprehensive analysis of Java/Android reference types and usage brought to you by the editor. I hope it will be helpful to you and support Wulin.com more~