前言

Github:https://github.com/HealerJean

博客:http://blog.healerjean.com

垃圾回收的机制主要是看对象是否有引用指向该对象。 java对象的引用包括
  强引用,软引用,弱引用,虚引用

1、强引用

强引用无需引入其他实体类,所引用的对象为 若该对象被清理将导致程序无法进行的对象。也就是平常最常使用的引用。JVM宁愿抛出OutOfMemory异常,也不会尝试回收所关联的对象。使用形式如下

当运行至Object[] objArr = new Object[1000];这句时,如果内存不足,JVM会抛出OOM错误也不会回收object指向的对象。不过要注意的是,当fun1运行完之后,object和objArr都已经不存在了,所以它们指向的对象都会被JVM回收。

public static void main(String[] args) {  
		  new Main().fun1();  
 }  
		       
public void fun1() {  
		Object object = new Object();  
	   Object[] objArr = new Object[1000];  
}  

2、软引用(java.lang.ref.SoftReference)

软引用需引入java.lang.ref.SoftReference类,所引用的对象为 仍有用但非必须的对象。被软引用关联的对象,内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用

作用:可以应用为某些缓存内容,加快程序速度,同时又不影响内存使用。比如网页缓存、图片缓存等。使用软引用能防止内存泄露,增强程序的健壮性。

也就是说,一旦SoftReference保存了对一个Java对象的软引用后,在垃圾线程对 这个Java对象回收前,SoftReference类所提供的get()方法返回Java对象的强引用。 另外,一旦垃圾线程回收该Java对象之 后,get()方法将返回null。


Object object=new Object();
SoftReference aSoftRef=new SoftReference(object);
aSoftRef.get();

package com.hlj.moudle.Java02垃圾收集器与内存分配策略;

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

/**
 * @Description 软引用
 * @Author HealerJean
 * @Date 2019/2/7  下午7:36.

   软引用需引入java.lang.ref.SoftReference类,
  所引用的对象为 仍有用但非必须的对象。被软引用关联的对象,将在抛出oom异常之前回收。
  可以应用为某些缓存内容,加快程序速度,同时又不影响内存使用。使用形式如下

 */
public class Jvm02Refqueue {


    @SuppressWarnings({ "rawtypes", "unchecked" })
    public static void main(String[] args) throws InterruptedException {

        //创建软引用
        ReferenceQueue<SoftReference<G>> rq = new ReferenceQueue<SoftReference<G>>();
        SoftReference[] srArr = new SoftReference[1000];

        //在 这个for循环中 new new G() 的时候
        //当执行到一定次数的是,会造成垃圾收集器回收内存(因为内存不够用了)
        for(int i = 0; i < srArr.length; i++){
            srArr[i] = new SoftReference(new G(), rq);
        }
        //获取被清除部分
        int n=0;
        for(int i = 0; i < srArr.length; i++){
            if(srArr[i].isEnqueued()){ //方法返回对象是否被垃圾回收器标记
                srArr[i]=null;
                n++;
            }
        }
        System.out.println("第一次GC,清除了"+n+"个");


        //下面的方法,会强制再执行一遍垃圾收集器,(用来测试软引用是否被回收)
        for(int i=0;i<10000;i++){
            G g=new G();
        }

        int m=0;
        for(int i = 0; i < srArr.length; i++){
            if(srArr[i]!=null&&srArr[i].isEnqueued()){
                srArr[i]=null;
                m++;
            }
        }
        System.out.println("第二次GC,清除了"+m+"个");
    }
}

//为了占据内存
class G{
    private  int [] big=new int[1000000];
}

/*
output:
第一次GC,清除了971个
第一次GC,清除了0个
*/


3、弱引用(java.lang.ref.WeakReference)

弱引用也是用来描述一些还有用,但并非必须存在的对象,它的强度会被软引用弱些,被弱引用关联的对象,只能生存到下一次GC前,当GC工作时,无论内存是否足够,都会回收掉弱引用关联的对象。JDK通过WeakReference类来实现。

当获取时,可通过weakReference.get方法获取,可能返回null

可传入一个ReferenceQueue对象到WeakReference构造,当引用对象被表示为可回收时,isEnqueued返回true


User user = new User();
WeakReference<User> weakReference = new WeakReference<User>(user);
weakReference.get();
	
ReferenceQueue<User> referenceQueue = new ReferenceQueue<User>();
WeakReference<User> weakReference2 = new WeakReference<User>(user, referenceQueue);
//如被被垃圾收集器回收,则返回true
weakReference.isEnqueued();

package com.hlj.moudle.Java02垃圾收集器与内存分配策略.Jvm02引用;

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

/**
 * @Description
 * @Author HealerJean
 * @Date 2019/2/7  下午8:25.
 */
public class Jvm02WeakReference {

    @SuppressWarnings({ "rawtypes", "unchecked" })
    public static void main(String[] args) throws InterruptedException {
        //创建弱引用
        ReferenceQueue<WeakReference<G>> rq = new ReferenceQueue<WeakReference<G>>();
        WeakReference[] srArr = new WeakReference[1000];

        for(int i = 0; i < srArr.length; i++){
            srArr[i] = new WeakReference(new G(), rq);
        }
        //获取被清除部分
        int n=0;
        for(int i = 0; i < srArr.length; i++){
            if(srArr[i].isEnqueued()){
                srArr[i]=null;
                n++;
            }
        }
        System.out.println("第一次GC,清除了"+n+"个");

        //尝试请求一次GC,防止上面不执行垃圾收集器
        System.gc();

        //获取第二次被清除部分
        int m=0;
        for(int i = 0; i < srArr.length; i++){
            if(srArr[i]!=null&&srArr[i].isEnqueued()){
                srArr[i]=null;
                m++;
            }
        }
        System.out.println("第一次GC,清除了"+m+"个");
    }
}
/*
output (第二次清除个数有明显变动)
第一次GC,清除了965个
第一次GC,清除了16个
*/

4、虚引用(PhantomReference)

虚引用与前面三种引用不同,并不是为了程序员干预对象的GC优先级。而是为了更精细的控制对象内存的释放, 必须与引用队列一同使用,当对象引用被释放时,其对象仍存在内存中,并未被释放,对象此时加入队列中,等待执行finalize函数。同时我们需要重写对象的finalize函数,帮助其释放内存。

虚引用称为“幻影引用”,它是最弱的一种引用关系,一个对象是否有虚引用的存在,完全不会对生存时间构成影响 。为一个对象设置虚引用关联的唯一目的就是希望能在这个对象被GC回收时收到一个系统通知。。通过PhantomReference类实现。

值得注意的是:phantomReference.get方法永远返回null, 当user从内存中删除时,调用isEnqueued会返回true


User user = new User();
ReferenceQueue<User> referenceQueue = new ReferenceQueue<User>();
PhantomReference<User>  phantomReference = new PhantomReference<User>(user, referenceQueue);
//即当user对象标识为可回收时,返回true
System.out.println(phantomReference.isEnqueued());
//永远返回null
System.out.println(phantomReference.get())

package com.hlj.moudle.Java02垃圾收集器与内存分配策略.Jvm02引用;

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;

/**
 * @Description
 * @Author HealerJean
 * @Date 2019/2/7  下午8:29.
 */
public class Jvm03PhantomReference {
        @SuppressWarnings({ "rawtypes", "unchecked" })
        public static void main(String[] args) throws InterruptedException {
            //创建弱引用
            ReferenceQueue<PhantomReference<G3>> rq = new ReferenceQueue<PhantomReference<G3>>();
            PhantomReference[] srArr = new PhantomReference[1000];

            for(int i = 0; i < srArr.length; i++){
                G3 g=new G3();
                srArr[i] = new PhantomReference(g, rq);
                //g = null;

            }
            //获取被清除部分
            int n = 0;
            for(int i = 0; i < srArr.length; i++){
                if(srArr[i].isEnqueued()){
                    srArr[i] = null;
                    n++;
                }
            }
            System.out.println("清除了"+n+"个");
        }
    }
    //为了占据内存
    class G3{
        private  int [] big=new int[1000000];
        @Override
        protected void finalize() throws Throwable {
            super.finalize();
            big=null;
        }
    }
/*
output
清除了826个
*/

ContactAuthor