[Reproduced] Java four references relationship

Disclaimer: This article is reprinted articles, reproduced, please include modifying the amount of the original source link and this statement is reproduced again.
Original link: https://blog.csdn.net/u013256816/article/details/50907595

Java provides four levels of references: a reference strong, soft, weak, and references cited imaginary, these four references in the package defined java.lang.refbelow:

Java source cited four kinds of relationships location

1 strong reference (Final Reference)

A strong reference refers to the prevalence in the program code, similar to Object obj = new Object()a reference, as long as there are strong references, the garbage collector will not go to recover these objects are referenced.

Strong reference has the following three characteristics:

1) strong reference can be directly accessed by the target;
2) strong reference point to lock an object at any time, the system will not be recovered --JVM would rather throw an exception OOM not recover strong reference object points;
3) strong references may cause memory leaks, such as adding a new List object out, after losing List is recovered, its internal objects can not be accessed, but the phenomenon will not be recovered.

All FinalReference class defined as follows:

package java.lang.ref;
/**
 * Final references, used to implement finalization
 */
class FinalReference<T> extends Reference<T> {
    public FinalReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
    }
}

FinalReference only a constructor: a strong reference according to reference a given object and reference queue structure.

2 soft references (Soft Reference)

Soft references are used to describe some, but not necessarily well as with objects: the soft references associated with the object, if sufficient memory, the garbage collector does not reclaim the object;
if memory is not enough, they will recover these objects.

The system will take place OutOfMemoryErrorbefore, JVM will be soft references associated with an object listed as the recovery range, and a second recovery. If, after the recovery of memory is still not enough, the system will be thrown OutOfMemoryError.

Providing JDK 1.2 from the start to achieve soft SoftReference class references: a reference to the queue (the ReferenceQueue) used in combination to achieve cache memory-sensitive - if the soft reference object is referenced garbage collected, JVM will put the soft references was added to a queue associated with a reference.

2.1 Case 1: garbage collection soft references

package com.healchow.java.detail;

import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;

public class SoftRefTest {
    private static ReferenceQueue<MyObject> softQueue = new ReferenceQueue<>();

    private static class MyObject {
        @Override
        protected void finalize() throws Throwable {
            super.finalize();
            System.out.println("MyObject's finalize called");
        }
        @Override
        public String toString() {
            return "I am MyObject";
        }
    }

    private static class CheckRefQueue implements Runnable {
        Reference<MyObject> obj = null;
        @Override
        public void run() {
            try {
                obj = (Reference<MyObject>) softQueue.remove();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (obj != null) {
                System.out.println("Object for SoftReference is " + obj.get());
            }
        }
    }
    
    public static void main(String[] args) {
        MyObject obj = new MyObject();
        SoftReference<MyObject> softRef = new SoftReference<>(obj, softQueue);
        new Thread(new CheckRefQueue()).start();

        // 删除强引用, 否则obj不会被回收
        obj = null;
        System.gc();
        System.out.println("After GC: Soft Get = " + softRef.get());
        System.out.println("尝试分配大块内存...");
        byte[] b = new byte[5 * 1024 * 725];
        System.out.println("After new byte[]: Soft Get = " + softRef.get());
        System.gc();
    }
}

(1) Test Method 1:

Set when running the test method VM main parameters: -Xmx5M, which is specified the program Java Heap maximum of 5MB, operating results as follows:

After GC: Soft Get = I am MyObject
尝试分配大块内存...
After new byte[]: Soft Get = I am MyObject
MyObject's finalize called
Object for SoftReference is null

Case Code explanation:

① First, construct the object MyObject, and assigned to the object variable, constitute strong references.

② Then use this construct SoftReference soft reference object MyObject softRef, and register to softQueue reference queue - when softRef be recycled, it will be added softQueue queue.

③ settings obj = null, delete the strong references, then the system reference only soft reference to MyObject object.

④ shows the call GC, soft cited by get () method to get a reference MyObject object, the object was not found to be recovered, indicating that GC in a well-memory conditions, will not recover soft reference object.

⑤ then requests a large heap space 5*1024*725(to be adjusted several times so that the work can proceed smoothly garbage collection, thread a smooth exit), this operation will make the nervous system heap memory usage, resulting in a new round of GC. After this GC , softRef.get()not to return MyObject object, but returns null -. Description of system memory in stressful situations, soft references are recycled soft references when it is recovered, it will be added to the queue referenced registration, this time with reference to the queue elements, opened multiple threads softQueue.remove()are no longer blocked, so the program is successful exit.

If the array above case again big change, for example 5*1024*1024, will throw OOM exception:

After GC: Soft Get = I am MyObject
尝试分配大块内存...
MyObject's finalize called
Exception in thread "main" Object for SoftReference is null
java.lang.OutOfMemoryError: Java heap space
    at com.healchow.java.detail.SoftRefTest.main(SoftRefTest.java:56)

(2) Test Method 2:

Set when running the test method VM main parameters: -Xmx5M -XX:PrintGCDetailsthe log information to print out the GC (GC logs can be viewed on "Java heap memory http://blog.csdn.net/u013256816/article/details/50764532"), operating results for the :

[GC (Allocation Failure) [PSYoungGen: 1024K->480K(1536K)] 1024K->480K(5632K), 0.0013139 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (System.gc()) [PSYoungGen: 1383K->480K(1536K)] 1383K->544K(5632K), 0.0011186 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (System.gc()) [PSYoungGen: 480K->0K(1536K)] [ParOldGen: 64K->504K(4096K)] 544K->504K(5632K), [Metaspace: 3316K->3316K(1056768K)], 0.0044642 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
After GC: Soft Get = I am MyObject
尝试分配大块内存...
[GC (Allocation Failure) [PSYoungGen: 38K->64K(1536K)] 542K->568K(5632K), 0.0009263 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 64K->32K(1536K)] 568K->536K(5632K), 0.0011345 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
[Full GC (Allocation Failure) [PSYoungGen: 32K->0K(1536K)] [ParOldGen: 504K->504K(4096K)] 536K->504K(5632K), [Metaspace: 3317K->3317K(1056768K)], 0.0038031 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 0K->0K(1536K)] 504K->504K(5632K), 0.0007999 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Allocation Failure) [PSYoungGen: 0K->0K(1536K)] [ParOldGen: 504K->486K(4096K)] 504K->486K(5632K), [Metaspace: 3317K->3317K(1056768K)], 0.0037241 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
MyObject's finalize called
Object for SoftReference is null
After new byte[]: Soft Get = null
[Full GC (System.gc()) [PSYoungGen: 59K->0K(1536K)] [ParOldGen: 4086K->4083K(4096K)] 4145K->4083K(5632K), [Metaspace: 3317K->3317K(1056768K)], 0.0036086 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
Heap
 PSYoungGen      total 1536K, used 10K [0x00000007bfe00000, 0x00000007c0000000, 0x00000007c0000000)
  eden space 1024K, 1% used [0x00000007bfe00000,0x00000007bfe02a68,0x00000007bff00000)
  from space 512K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007bff80000)
  to   space 512K, 0% used [0x00000007bff80000,0x00000007bff80000,0x00000007c0000000)
 ParOldGen       total 4096K, used 4083K [0x00000007bfa00000, 0x00000007bfe00000, 0x00000007bfe00000)
  object space 4096K, 99% used [0x00000007bfa00000,0x00000007bfdfcfc0,0x00000007bfe00000)
 Metaspace       used 3324K, capacity 4564K, committed 4864K, reserved 1056768K
  class space    used 366K, capacity 388K, committed 512K, reserved 1048576K

2.2 Case 2: Use a soft reference cache

public class BitMapManager {
    private Map<String, SoftReference<Bitmap>> imageCache = new HashMap<>();

    // 保存Bitmap的软引用到HashMap
    public void saveBitmapToCache(String path) {
        // 强引用的Bitmap对象
        Bitmap bitmap = BitmapFactory.decodeFile(path);
        // 软引用的Bitmap对象
        SoftReference<Bitmap> softBitmap = new SoftReference<Bitmap>(bitmap);
        // 添加该对象到Map中使其缓存
        imageCache.put(path, softBitmap);
        // 使用完后手动将位图对象置null
        bitmap = null;
    }

    public Bitmap getBitmapByPath(String path) {
        // 从缓存中取软引用的Bitmap对象
        SoftReference<Bitmap> softBitmap = imageCache.get(path);
        // 判断是否存在软引用
        if (softBitmap == null) {
            return null;
        }
        // 取出Bitmap对象,如果由于内存不足Bitmap被回收,将取得空
        Bitmap bitmap = softBitmap.get();
        return bitmap;
    }
}

2.3 application scenario of a soft reference

Soft references are mainly used for memory-sensitive cache frequently used in the Android system. Most Android apps will use a lot of pictures. Since the hardware needed to read the file operation is slow, so consider putting your images cached, need when read directly from memory.

However, due to the relatively large memory space occupied pictures, lots of pictures cache may easily occur OutOfMemoryError, then we can consider the use of soft references techniques to avoid this problem.

SoftReference can solve the problem of the OOM: each object is instantiated, the object will be saved in the form of cache, and when you call the object again, you can directly through the soft references by soft references get()resource data obtained method object when. memory will take place when the OOM, GC will quickly remove all the soft references to prevent OOM occurs.

3 Weak references (Weak Reference)

Weak references used to describe non-essential object, its strength is weaker, weak reference object is associated only to survive until the next garbage collection occurs when the garbage collector job, regardless of whether the current memory than enough soft referenced, recovering lost only weakly referenced objects associated Once a weak reference object is garbage collected, it will be added to a queue registration reference.

We slightly modify the code on a Case 1:

package com.healchow.java.detail;

import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;

public class WeakRefTest {
    private static ReferenceQueue<MyObject> weakQueue = new ReferenceQueue<>();

    private static class MyObject {
        @Override
        protected void finalize() throws Throwable {
            super.finalize();
            System.out.println("MyObject's finalize called");
        }
        @Override
        public String toString() {
            return "I am MyObject";
        }
    }

    private static class CheckRefQueue implements Runnable {
        Reference<MyObject> obj = null;
        @Override
        public void run() {
            try {
                obj = (Reference<MyObject>)weakQueue.remove();
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
            if(obj != null) {
                System.out.println("删除的弱引用为: " + obj);
                System.out.println("获取弱引用的对象 obj.get() 为: " + obj.get());
            }
        }
    }

    public static void main(String[] args) {
        MyObject object = new MyObject();
        Reference<MyObject> weakRef = new WeakReference<>(object,weakQueue);
        System.out.println("创建的弱引用为: " + weakRef);
        new Thread(new CheckRefQueue()).start();

        object = null;
        System.out.println("Before GC: Weak Get = " + weakRef.get());
        System.gc();
        System.out.println("After GC: Weak Get = " + weakRef.get());
    }
}

(1) demonstration of the method - does not modify the JVM parameters:

Operating results as follows:

创建的弱引用为: java.lang.ref.WeakReference@6f94fa3e
Before GC: Weak Get = I am MyObject
After GC: Weak Get = null
删除的弱引用 obj 为: java.lang.ref.WeakReference@6f94fa3e
但是获取弱引用的对象 obj.get() 为: null
MyObject's finalize called

can be seen:

Before the GC, weak reference object has not been found that the garbage collector, and therefore by weakRef.get()reference to the corresponding object can be acquired.

But as long as garbage collection, weak references will be found, and was immediately recovered and added registration reference queue. Until then tries weakRef.get()will fail to obtain the object reference.

(2) a weak reference usage scenarios:

Weak references refer to the use of scenarios java.util.WeakHashMap.

Soft references, weak references are very suitable to hold the cached data for those dispensable. Insufficient system memory, the cache data will be recovered, it will not cause a memory leak. When sufficient memory resources, which in turn can cache data present for a long time, thereby improving the response speed of the system used.

4 dangling reference (Phantom Reference)

Virtual reference, also known as ghost or apparition cited references, it is the weakest kind of phantom reference to an object reference relationship holds, and no reference is almost the same - at any time are likely to be garbage collected.

When trying to pass a virtual reference get()when obtaining strong reference method will always fail.

And it must be used with reference to an imaginary reference queue, its role is to track the garbage collection process.

References virtual get()method always returns null, which is implemented as follows:

public T get() {
    return null;
}

Let us modify the first two Code Case 1:

package com.healchow.java.detail;

import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.concurrent.TimeUnit;

public class PhantomRefTest {
    private static ReferenceQueue<MyObject> phantomQueue = new ReferenceQueue<>();

    private static class MyObject {
        @Override
        protected void finalize() throws Throwable {
            super.finalize();
            System.out.println("MyObject's finalize called");
        }
        @Override
        public String toString() {
            return "I am MyObject";
        }
    }

    private static class CheckRefQueue implements Runnable {
        Reference<MyObject> obj = null;
        @Override
        public void run() {
            try {
                obj = (Reference<MyObject>) phantomQueue.remove();
                System.out.println("删除的虚引用 obj 为: " + obj);
                System.out.println("但是获取虚引用的对象 obj.get() 为: " + obj.get());
                System.exit(0);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyObject object = new MyObject();
        Reference<MyObject> phantomRef = new PhantomReference<>(object, phantomQueue);
        System.out.println("创建的虚引用为:" + phantomRef);
        new Thread(new CheckRefQueue()).start();

        object = null;
        TimeUnit.SECONDS.sleep(1);
        int i = 1;
        while (true) {
            System.out.println("第" + i++ + "次gc");
            System.gc();
            TimeUnit.SECONDS.sleep(1);
        }
    }
}

(1) demonstration of the method - does not modify the JVM parameters:

Operating results as follows:

创建的虚引用为:java.lang.ref.PhantomReference@6f94fa3e
第1次gc
MyObject's finalize called
第2次gc
删除的虚引用 obj 为: java.lang.ref.PhantomReference@6f94fa3e
但是获取虚引用的对象 obj.get() 为: null

can be seen:

After a GC, the system finds a garbage object and call finalize () method to reclaim memory, but did not immediately join the Phantom reference objects recovered queue.

The second time GC, GC the object is actually cleared at this time is added to the virtual reference object referenced virtual queue.

(2) references virtual usage scenarios:

The maximum effect of phantom reference is to track the object recovery, clean-up resources are destroying objects.

When objects are not normally used, the object's class overloads finalize()the method can be recycled resource objects but if accidentally, so that the object will override this example resurrected. finalize()Method:

public class Test {
    private static Test obj;
    
    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        obj = this;
    }
}

Creating Test Objects: obj = new Test();, then so obj = null;, after calling System.gc()an attempt to destroy the object.

But I'm sorry, no matter how many times you call System.gc()to no avail, unless again obj = null;to reclaim objects.

The reason: the JVM for each object only once at most be overridden finalize()methods, sample code, the super.finalize()later was assigned to obj so that obj revived, it rewrites the finalize () method is never called second times.

(3) clean up the object through the virtual reference

The above description of small fragments rewrite finalize()method is not very reliable, we can use a virtual reference to clean up resources occupied by the object code is modified as follows:

package com.healchow.java.detail;

import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class PhantomRefTest2 {
    private static ReferenceQueue<MyObject> phantomQueue = new ReferenceQueue<>();
    private static Map<Reference<MyObject>, String> resourceMap = new HashMap<>();

    private static class MyObject {
        @Override
        protected void finalize() throws Throwable {
            super.finalize();
            System.out.println("MyObject's finalize called");
        }
        @Override
        public String toString() {
            return "I am MyObject";
        }
    }

    private static class CheckRefQueue implements Runnable {
        Reference<MyObject> refObj = null;

        @Override
        public void run() {
            try {
                refObj = (Reference<MyObject>) phantomQueue.remove();
                // 从资源Map中移除弱引用对象, 即手动释放资源
                Object value = resourceMap.get(refObj);
                System.out.println("clean resource: " + value);
                resourceMap.remove(refObj);

                System.out.println("删除的虚引用为: " + refObj);
                System.out.println("获取虚引用的对象 obj.get() 为: " + refObj.get());
                System.exit(0);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyObject object = new MyObject();
        Reference<MyObject> phantomRef = new PhantomReference<>(object, phantomQueue);
        System.out.println("创建的虚引用为: " + phantomRef);
        new Thread(new CheckRefQueue()).start();
        // 将创建的虚引用对象存入资源Map
        resourceMap.put(phantomRef, "Some Resources");

        object = null;
        TimeUnit.SECONDS.sleep(1);
        int i = 1;
        while (true) {
            System.out.println("第" + i++ + "次gc");
            System.gc();
            TimeUnit.SECONDS.sleep(1);
        }
    }
}

operation result:

创建的虚引用为: java.lang.ref.PhantomReference@6f94fa3e
第1次gc
MyObject's finalize called
第2次gc
clean resource: Some Resources
删除的虚引用 obj 为: java.lang.ref.PhantomReference@6f94fa3e
但是获取虚引用的对象 obj.get() 为: null


Reference material

"Java Performance Tuning - let your Java programs faster and more stable," Ge Yiming, eds.

"Java heap memory http://blog.csdn.net/u013256816/article/details/50764532 "

Copyright Notice

This article belongs to original author, if infringement, please contact the blogger, certainly removed immediately.

To reprint, please indicate the original link in the apparent position of the article page, or else your own risk.

Guess you like

Origin www.cnblogs.com/shoufeng/p/11491392.html