精华内容
参与话题
问答
  • 就是一个强引用; 垃圾回收器不会回收它?那么这个Object具体指的时什么啊? 举例: //时间工具类 public clss DateUtils(){ //这里我不加static,在下面通过new的方式获取 public String getDate(){ ...
  • 下面的代码为什么能避免强引用循环? cell.thumbnailView.image = item.thumbnail; __weak BNRItemCell *weakCell = cell; cell.actionBlock = ^{ NSLog(@"Going to show image for %@", item); ...
  • 强引用,软引用,弱引用,虚引用

    千次阅读 2015-04-21 14:44:38
    强引用,软引用,弱引用,虚引用 强引用: 我们一般使用的就是强引用。垃圾回收器绝不会回收它。 当内存空间不足时Java虚拟机宁愿抛出OutOfMemoryError错误使程序异常终止,也不会回收具有强引用的对象来解决内存不足...


    强引用,软引用,弱引用,虚引用



    强引用:
    我们一般使用的就是强引用。垃圾回收器绝不会回收它。
    当内存空间不足时Java虚拟机宁愿抛出OutOfMemoryError错误使程序异常终止,也不会回收具有强引用的对象来解决内存不足的问题


    软引用:
    如果一个对象具有软引用,那么当内存空间足够的时候GC就不会回收它,如果内存空间不足了,就会回收这些对象的内存空间。


    弱引用:

    如果一个对象具有弱引用,那么当GC线程扫描的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。

    其实准备地说应该是"如果一个对象只具有弱引用.........",即仅有弱引用而不存在对其的强引用才会将其回收.

    但由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。




    为了防止内存溢出,在处理一些占用内存大而且声明周期较长的对象时候,可以尽量应用软引用和弱引用.
    但是也请注意在Android较老版本中,常用软引用或弱引用 (SoftReference or WeakReference)实现内存缓存技术。
    但从 Android 2.3 (API Level 9)开始,GC会更倾向于回收持有软引用或弱引用的对象,这让软引用和弱引用变得不再可靠。


    虚引用:
    顾名思义,“虚引用”就是形同虚设,与其他三种引用都不同它并不会决定对象的生命周期。
    如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。
    虚引用主要用来跟踪对象被垃圾回收器回收的活动。
    展开全文
  • 在Java中提供了4个级别的引用:强引用,软引用,弱引用,虚引用。在这4个引用级别中,只有强引用FinalReference类是包内可见,其他3中引用类型均为public,可以在应用程序中直接使用。 强引用 Java中的引用,有点像...

    在Java中提供了4个级别的引用:强引用,软引用,弱引用,虚引用。在这4个引用级别中,只有强引用FinalReference类是包内可见,其他3中引用类型均为public,可以在应用程序中直接使用。

    强引用

    Java中的引用,有点像C++的指针,通过引用,可以对堆中的对象进行操作。
    在我们的代码生涯中,大部分使用的都是强引用,所谓强引入,都是形如Object o = new Object()的操作。
    强引用具备一下特点:

    • 强引用可以直接访问目标对象
    • 强引用所指向的对象在任何时候不会被系统回收,JVM宁愿抛出OOM异常,也不回收强引用所指向的对象
    • 强引用可能导致内存泄漏

    所以当我们在使用强引用创建对象时,如果下面不使用这个对象了,一定要显式地使用o = null操作来辅助垃圾回收器进行gc操作。一旦我们没有进行置null操作,就会造成内存泄漏,再使用MAT等工具进行复杂操作,浪费了大量的时间。
    在jdk代码中也有许多显式置null的操作。对于ArrayList,相信了解过java的都知道,ArrayList底层使用的数组实现的,在我们进行clear操作时,就会对数组进行置null操作。

        public void clear() {
            modCount++;
    
            // clear to let GC do its work
            for (int i = 0; i < size; i++)
                elementData[i] = null;
    
            size = 0;
        }
    

    其实如果我们的对象Object o = new Object()是在方法内创建的,那么局部变量o将被分配在栈上,而对象Object实例被分配在堆上,局部变量o指向Object实例所在的对空间,通过o可以操作该实例,那么o就是Object的引用。这时候显式置null的作用不大,只要在我们的方法退出,即该栈桢从Java虚拟机栈弹出时,o指向Object的引用就断开了,此时Object在堆上分配的内存在GC时就能被回收。

    软引用

    软引用是除强引用外,最强的引用类型。可以通过java.lang.ref.SoftReference使用软引用,一个持有软引用的对象,不会被JVM很快回收,JVM会根据当前堆的使用情况来判断何时回收,当堆使用率临近阈值时,才会去回收软引用对象。只要有足够的内存,软引用便可能在内存中存活相当长一段时间。因此,软引用可以用于实现对内存敏感的Cache。
    在java doc中,软引用是这样描述的

    虚拟机在抛出 OutOfMemoryError 之前会保证所有的软引用对象已被清除。此外,没有任何约束保证软引用将在某个特定的时间点被清除,或者确定一组不同的软引用对象被清除的顺序。不过,虚拟机的具体实现会倾向于不清除最近创建或最近使用过的软引用。

    举个例子

    /**
     *
     * @author xiaosuda
     * @date 2018/10/23
     */
    public class ReferenceTest {
    
    
        public static void main(String[] args) {
    
            //强引用
            MyObject object = new MyObject();
            //创建引用队列
            ReferenceQueue<MyObject> queue = new ReferenceQueue<>();
            //创建软引用
            SoftReference<MyObject> softRef = new SoftReference<>(object, queue);
            //检查引用队列,监控对象回收情况
            new Thread(new CheckRefQueue(queue)).start();
            //删除强引用
            object = null;
            //手动GC
            System.gc();
            System.out.println("After GC:Soft Get= " + softRef.get());
            System.out.println("分配大内存:" + Runtime.getRuntime().maxMemory());
            try {
                //分配大内容
                  byte[] maxObject = new byte[(int) Runtime.getRuntime().maxMemory()];
            } catch (Throwable e) {
                System.out.println(e.getMessage());
            }
            System.out.println("After new byte[]:Soft Get= " + softRef.get());
        }
    
    }
    
    class CheckRefQueue implements Runnable {
    
        ReferenceQueue queue;
    
        public CheckRefQueue(ReferenceQueue queue) {
            this.queue = queue;
        }
    
        @Override
        public void run() {
            Reference myObj = null;
            try {
                myObj = queue.remove();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (myObj != null) {
                System.out.println("Object for SoftReference is " + myObj.get());
            }
        }
    }
    
    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";
        }
    }
    
    

    JVM参数为:-Xmx5m -XX:+PrintGCDetails -Xmn2m
    执行结果如下:

    [GC (System.gc()) [PSYoungGen: 891K->496K(1536K)] 891K->520K(5632K), 0.0015474 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
    [Full GC (System.gc()) [PSYoungGen: 496K->0K(1536K)] [ParOldGen: 24K->425K(4096K)] 520K->425K(5632K), [Metaspace: 2687K->2687K(1056768K)], 0.0050401 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] 
    After GC:Soft Get= I'am MyObject
    分配大内存:5767168
    [GC (Allocation Failure) [PSYoungGen: 20K->64K(1536K)] 445K->489K(5632K), 0.0002611 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
    [GC (Allocation Failure) [PSYoungGen: 64K->96K(1536K)] 489K->521K(5632K), 0.0002294 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
    [Full GC (Allocation Failure) [PSYoungGen: 96K->0K(1536K)] [ParOldGen: 425K->414K(4096K)] 521K->414K(5632K), [Metaspace: 2688K->2688K(1056768K)], 0.0037219 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
    [GC (Allocation Failure) [PSYoungGen: 0K->0K(1536K)] 414K->414K(5632K), 0.0007248 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
    [Full GC (Allocation Failure) [PSYoungGen: 0K->0K(1536K)] [ParOldGen: 414K->402K(4096K)] 414K->402K(5632K), [Metaspace: 2688K->2688K(1056768K)], 0.0047190 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] 
    异常:Java heap space
    MyObject's finalize called
    Object for SoftReference is null
    After new byte[]:Soft Get= null
    Heap
     PSYoungGen      total 1536K, used 81K [0x00000007bfe00000, 0x00000007c0000000, 0x00000007c0000000)
      eden space 1024K, 7% used [0x00000007bfe00000,0x00000007bfe14760,0x00000007bff00000)
      from space 512K, 0% used [0x00000007bff80000,0x00000007bff80000,0x00000007c0000000)
      to   space 512K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007bff80000)
     ParOldGen       total 4096K, used 402K [0x00000007bfa00000, 0x00000007bfe00000, 0x00000007bfe00000)
      object space 4096K, 9% used [0x00000007bfa00000,0x00000007bfa649d8,0x00000007bfe00000)
     Metaspace       used 2694K, capacity 4490K, committed 4864K, reserved 1056768K
      class space    used 290K, capacity 386K, committed 512K, reserved 1048576K
    
    Process finished with exit code 0
    
    

    在这个例子中,首先构造MyObject对象,并将其赋值给obj变量,构成强引用。然后使用弱引用构造这个MyObject对象的软引用,并注册导softQueue队列里面。当softRef被回收时,会被softQueue队列,设置obj=null,删除这个强引用。因此,系统内对MyObject对象的引用只剩下软引用。此时显示调用GC,通过软引用的get方法,取得myObject对象实例的强引用。法相对象未被回收。说明在GC充足情况下不会回收软引用对象。
    接着申请一块堆大小的的堆空间,并catch异常,从执行结果发现,在这次GC后,softRef.get()不再返回MyObject对象,而是返回null。说明,在系统内存紧张的情况下,软引用被回收并且加入注册的引用队列
    软引用在我们的日常开发中使用的场景很多,比如商城中商品的信息。某个商品可能会被多人访问,此时我们可以把该商品的信息使用软引用保存。当系统内存足够时,可以实现高速查找,当系统内存不足又会被回收,避免OOM的风险。

    TIPS: 尽管软引用会在OOM之前被清理,但是,这并不表示full gc 会清理软引用对象。在经过full gc后我们的软引用对象都放入了old区,由于full gc的存在,程序大多数强框下并不会OOM。由于软引用对象占据了老年代的空间,full gc将执行的更为频繁。所以还是建议使用弱引用

    当然了,上面的例子是OOM之前回收软引用。怎么才能full gc就回收软引用对象呢?

    -XX:SoftRefLRUPolicyMSPerMB // FullGC 保留的 SoftReference 数量,参数值越大,GC 后保留的软引用对象就越多。
    

    当我们设置这个参数值为0时,full gc就会回收我们的软引用对象了

    修改main方法内容

     public static void main(String[] args) {
    
            //强引用
            MyObject object = new MyObject();
            //创建引用队列
            ReferenceQueue<MyObject> queue = new ReferenceQueue<>();
            //创建软引用
            SoftReference<MyObject> softRef = new SoftReference<>(object, queue);
            //检查引用队列,监控对象回收情况
            new Thread(new CheckRefQueue(queue)).start();
            //删除强引用
            object = null;
            //手动GC
            System.gc();
            System.out.println("After new byte[]:Soft Get= " + softRef.get());
        }
    
    

    JVM参数-Xmx5m -XX:+PrintGCDetails -Xmn2m -XX:SoftRefLRUPolicyMSPerMB=0
    执行结果

    [GC (System.gc()) [PSYoungGen: 890K->496K(1536K)] 890K->520K(5632K), 0.0021185 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
    [Full GC (System.gc()) [PSYoungGen: 496K->0K(1536K)] [ParOldGen: 24K->413K(4096K)] 520K->413K(5632K), [Metaspace: 2685K->2685K(1056768K)], 0.0071067 secs] [Times: user=0.01 sys=0.01, real=0.01 secs] 
    After new byte[]:Soft Get= null
    Object for SoftReference is null
    MyObject's finalize called
    Heap
     PSYoungGen      total 1536K, used 71K [0x00000007bfe00000, 0x00000007c0000000, 0x00000007c0000000)
      eden space 1024K, 6% used [0x00000007bfe00000,0x00000007bfe11e68,0x00000007bff00000)
      from space 512K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007bff80000)
      to   space 512K, 0% used [0x00000007bff80000,0x00000007bff80000,0x00000007c0000000)
     ParOldGen       total 4096K, used 413K [0x00000007bfa00000, 0x00000007bfe00000, 0x00000007bfe00000)
      object space 4096K, 10% used [0x00000007bfa00000,0x00000007bfa67608,0x00000007bfe00000)
     Metaspace       used 2693K, capacity 4490K, committed 4864K, reserved 1056768K
      class space    used 290K, capacity 386K, committed 512K, reserved 1048576K
    
    Process finished with exit code 0
    
    

    可以发现在手动GC后,软引用对象已经被回收。此时的软引用已经与弱引用效果一样了。下面看弱引用

    弱引用

    弱引用时一种比软引用较弱的引用类型。在系统GC时,只要发现弱引用,不管系统对空间是否足够,都会对对象进行回收。但是,由于垃圾回收器的线程通常优先级很低,因此,并不一定能很快地发现持有弱引用的对象。在这种情况下,弱引用对象可以存在较长时间。一旦一个弱引用对象被垃圾收集器回收,便会加入导一个注册引用队列中
    修改软引用例子中的main方法内容为

        public static void main(String[] args) {
    
           //强引用
            MyObject object = new MyObject();
            //创建引用队列
            ReferenceQueue<MyObject> queue = new ReferenceQueue<>();
            WeakReference<MyObject> weakRef = new WeakReference<>(object, queue);
            new Thread(new CheckRefQueue(queue)).start();
            object = null;
            System.out.println("After new byte[]:Soft Get= " + weakRef.get());
            System.gc();
            System.out.println("After new byte[]:Soft Get= " + weakRef.get());
       }
    

    JVM参数:-Xmx5m -XX:+PrintGCDetails -Xmn2m
    执行结果如下

    After new byte[]:Soft Get= I'am MyObject
    [GC (System.gc()) [PSYoungGen: 891K->496K(1536K)] 891K->520K(5632K), 0.0016576 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
    [Full GC (System.gc()) [PSYoungGen: 496K->0K(1536K)] [ParOldGen: 24K->426K(4096K)] 520K->426K(5632K), [Metaspace: 2685K->2685K(1056768K)], 0.0124398 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] 
    MyObject's finalize called
    Object for SoftReference is null
    After new byte[]:Soft Get= null
    Heap
     PSYoungGen      total 1536K, used 71K [0x00000007bfe00000, 0x00000007c0000000, 0x00000007c0000000)
      eden space 1024K, 6% used [0x00000007bfe00000,0x00000007bfe11e60,0x00000007bff00000)
      from space 512K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007bff80000)
      to   space 512K, 0% used [0x00000007bff80000,0x00000007bff80000,0x00000007c0000000)
     ParOldGen       total 4096K, used 426K [0x00000007bfa00000, 0x00000007bfe00000, 0x00000007bfe00000)
      object space 4096K, 10% used [0x00000007bfa00000,0x00000007bfa6a988,0x00000007bfe00000)
     Metaspace       used 2692K, capacity 4490K, committed 4864K, reserved 1056768K
      class space    used 290K, capacity 386K, committed 512K, reserved 1048576K
    
    Process finished with exit code 0
    
    

    通过结果可以看到,在GC之前,弱引用对象并未被垃圾回收器发现,因此通过weakRef.get()方法可以获得对应的强引用,但是只要进行垃圾回收,弱引用对象一旦被发现,便会立刻被回收,并加入注册的引用队列中。此时,再通过weakRef.get()方法取得强引用就会失败

    虚引用在我们的日常代码中也经常用到,比如ThreadLocal的内部实现就是一个ThreadLocalMap,该mapEntrykeyThreadLocal本身,value为我们向ThreadLocal对象set的值,其中的key就是弱引用对象。又比如
    集合WeakHashMap,都是使用了弱引用实现的,想更加深了解的可以区看看相关源码的实现。

    虚引用

    虚引用时所有引用类型中最弱的一个,一个持有弱引用的对象,和没有引用几乎是一样的,随时都可能被垃圾回收器回收。当试图通过虚引用的get()方法取得强引用时,总会失败。并且,虚引用必须和引用队列一起使用,它的作用在于跟踪垃圾回收过程。当垃圾回收器准备回收一个对象时,如果发现他还有虚引用,就会在垃圾回收后销毁这个对象,将这个对象加入引用队列。虚引用主要用于检测对象是否已经从内存中删除。

    展开全文
  • 强引用: Java中的引用,有点像C++的指针。通过引用,可以对堆中的对象进行操作。在某函数中,当创建了一个对象,该对象被分配在堆中,通过这个对象的引用才能对这个对象进行操作。StringBuffer str=new Strin

    用了Java怎么长时间一直不知道原来Java还有四种引用类型,这个引用类型和我们平常说的可不一样。这里的引用类型不是指数据类型的一种,而是指Java中的引用所分的四种类型。他们代表了JVM回收内存的四种强度,分别如下。

    强引用:

    Java中的引用,有点像C++的指针。通过引用,可以对堆中的对象进行操作。在某函数中,当创建了一个对象,该对象被分配在堆中,通过这个对象的引用才能对这个对象进行操作。

    Object o=new Object();

    假设以上代码是在函数体内运行的,那么局部变量o将被分配在栈上,而对象实例,被分配在堆上。局部变量o指向Object实例所在的堆空间,通过o可以操作该实例,那么o就是Object的引用。


    如果再创建一个赋值语句

    Object oj=o;
    那么o指向的Object内存空间也会被oj所指向,此时我们可以说oj==o,那么ob.equals也肯定相等,即两个对象的值也肯定一样,当修改了o对象的时候,oj对象也会发生变化,或者当修改了oj对象的时候o对象也肯定会变化。所以如果想复制另外一个对象的值的话千万不要用这种方式,在多线程的情况下可能会有更槽糕的情况发生,你可以使用JDK自带的克隆方法,也可以重写克隆方法。

    public class Test1 {
    			public static void main(String[] args) {
    				student S=new student("1","我是大s");
    				student s=S;
    				System.out.println(s==S); //true
    				System.out.println(s.equals(S)); //true
    				System.out.println("打印出大S"+S); //id=1
    				System.out.println("打印出小s"+s); //id=1
    				S.setId("2");
    				System.out.println("修改后的大S"+S);  //id=2
    				System.out.println("未修改后的小s"+s); //id=2
    				s.setId("3");
    				System.out.println("未修改后的大S"+S); //id=3
    				System.out.println("修改后的小s"+s); //id=3
    	
    			}
    }
    class student{
    	String name;
    	String id;
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	public String getId() {
    		return id;
    	}
    	public void setId(String id) {
    		this.id = id;
    	}
    	public student(String name, String id) {
    		super();
    		this.name = name;
    		this.id = id;
    	}
    	@Override
    	public String toString() {
    		return "student [name=" + name + ", id=" + id + "]";
    	}
    	
    	
    }




    上例中的大S和小S都是强引用,强引用具有如下特点:

    1.强引用可以直接访问目标对象。

    2.强引用所指向的对象在任何时候都不会被系统回收。JVM宁愿抛出OOM异常,也不会回收强引用所指向的对象。

    3.强引用可能导致内存泄漏,为了避免内存泄漏,在使用完成之后我们可以把字符串对象设置为null,如果是集合的话可以使用

    List list=new ArrayList<>();
    list.clear();

    软引用:

    软引用的强度是仅次于强引用的,如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。   

    我们可以使用java.lang.ref.SoftReference来创建软引用;

    String str=new String("abc");                                     // 强引用
    SoftReference<String> softRef=new SoftReference<String>(str);     // 软引用
    当内存不足时,等价于:

    If(JVM.内存不足()) {
       str = null;  // 转换为软引用
       System.gc(); // 垃圾回收器进行回收
    }

    弱引用:

    弱引用的强度比软引用更次,也就是说只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。

    如果这个对象是偶尔的使用,并且希望在使用时随时就能获取到,但又不想影响此对象的垃圾收集,那么你应该用 Weak Reference 来标记此对象。

    String str=new String("abc");    
    WeakReference<String> abcWeakRef = new WeakReference<String>(str);
    str=null;
    如果你想把这个对象变成强引用的话可以使用

    String  abc = abcWeakRef.get();

    弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。

    当你想引用一个对象,但是这个对象有自己的生命周期,你不想介入这个对象的生命周期,这时候你就是用弱引用。

    这个引用不会在对象的垃圾回收判断中产生任何附加的影响。

    public class ReferenceTest {
    
    	private static ReferenceQueue<VeryBig> rq = new ReferenceQueue<VeryBig>();
    
    	public static void checkQueue() {
    		Reference<? extends VeryBig> ref = null;
    		while ((ref = rq.poll()) != null) {
    			if (ref != null) {
    				System.out.println("In queue: "	+ ((VeryBigWeakReference) (ref)).id);
    			}
    		}
    	}
    
    	public static void main(String args[]) {
    		int size = 3;
    		LinkedList<WeakReference<VeryBig>> weakList = new LinkedList<WeakReference<VeryBig>>();
    		for (int i = 0; i < size; i++) {
    			weakList.add(new VeryBigWeakReference(new VeryBig("Weak " + i), rq));
    			System.out.println("Just created weak: " + weakList.getLast());
    
    		}
    
    		System.gc(); 
    		try { // 下面休息几分钟,让上面的垃圾回收线程运行完成
    			Thread.currentThread().sleep(6000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		checkQueue();
    	}
    }
    
    class VeryBig {
    	public String id;
    	// 占用空间,让线程进行回收
    	byte[] b = new byte[2 * 1024];
    
    	public VeryBig(String id) {
    		this.id = id;
    	}
    
    	protected void finalize() {
    		System.out.println("Finalizing VeryBig " + id);
    	}
    }
    
    class VeryBigWeakReference extends WeakReference<VeryBig> {
    	public String id;
    
    	public VeryBigWeakReference(VeryBig big, ReferenceQueue<VeryBig> rq) {
    		super(big, rq);
    		this.id = big.id;
    	}
    
    	protected void finalize() {
    		System.out.println("Finalizing VeryBigWeakReference " + id);
    	}
    }

    虚引用

    虚引用顾名思义就是形同虚设,虚引用也称为幻影引用:一个对象是都有虚引用的存在都不会对生存时间都构成影响,也无法通过虚引用来获取对一个对象的真实引用。唯一的用处:能在对象被GC时收到系统通知,JAVA中用PhantomReference来实现虚引用。

    对比不同:


    class Grocery {
    		private static final int SIZE = 10000;
    		// 属性d使得每个Grocery对象占用较多内存,有80K左右
    		private double[] d = new double[SIZE];
    		private String id;
    		public Grocery(String id) {
    			this.id = id;
    		}
    		public String toString() {
    			return id;
    		}
    		public void finalize() {
    			System.out.println("即将回收 " + id);
    		}
    	}
    	public class References {
    		private static ReferenceQueue<Grocery> rq = new ReferenceQueue<Grocery>();
    		public static void checkQueue() {
    			Reference<? extends Grocery> inq = rq.poll(); // 从队列中取出一个引用
    			if (inq != null)
    				System.out.println("In queue: " + inq + " : " + inq.get());
    		}
    		public static void main(String[] args) {
    			final int size = 10;
    			// 创建10个Grocery对象以及10个软引用
    			Set<SoftReference<Grocery>> sa = new HashSet<SoftReference<Grocery>>();
    			for (int i = 0; i < size; i++) {
    				SoftReference<Grocery> ref = new SoftReference<Grocery>(
    						new Grocery("软引用 " + i), rq);
    				System.out.println("刚刚 创建了: " + ref.get());
    				sa.add(ref);
    			}
    			System.gc();
    			checkQueue();
    			// 创建10个Grocery对象以及10个弱引用
    			Set<WeakReference<Grocery>> wa = new HashSet<WeakReference<Grocery>>();
    			for (int i = 0; i < size; i++) {
    				WeakReference<Grocery> ref = new WeakReference<Grocery>(
    						new Grocery("弱引用 " + i), rq);
    				System.out.println("刚刚 创建了: " + ref.get());
    				wa.add(ref);
    			}
    			System.gc();
    			checkQueue();
    			// 创建10个Grocery对象以及10个虚引用
    			Set<PhantomReference<Grocery>> pa = new HashSet<PhantomReference<Grocery>>();
    			for (int i = 0; i < size; i++) {
    				PhantomReference<Grocery> ref = new PhantomReference<Grocery>(
    						new Grocery("abc " + i), rq);
    				System.out.println("刚刚 创建了: " + ref.get());
    				pa.add(ref);
    			}
    			System.gc();
    			checkQueue();
    		}
    }
    在上面的这个例子中,依次创建了十个10个软引用、10个弱引用和10个虚引用,它们各自引用一个Grocery对象。并且在创建之后调用GC方法。从程序运行时的打印结果可以看出,虚引用形同虚设,它所引用的对象随时可能被垃圾回收,具有弱引用的对象拥有稍微长的生命周期,当垃圾回收器执行回收操作时,有可能被垃圾回收,具有软引用的对象拥有较长的生命周期,但在Java虚拟机认为内存不足的情况下,也会被垃圾回收。

    总结

    强引用:就像是老板(OOM)的亲儿子一样,在公司可以什么事都不干,但是千万不要老是占用公司的资源为他自己做事,记得用完公司的妹子之后,要让她们去工作(资源要懂得释放) 不然公司很可能会垮掉的。
    软引用:有点像老板(OOM)的亲戚,在公司表现不好有可能会被开除,即使你投诉他(调用GC)上班看片,但是只要不被老板看到(被JVM检测到)就不会被开除(被虚拟机回收)。
    弱引用:就是一个普通的员工,平常如果表现不佳会被开除(对象没有其他引用的情况下),遇到别人投诉(调用GC)上班看片,那开除是肯定了(被虚拟机回收)。
    虚引用:这货估计就是个实习生跟临时工把,遇到事情的时候想到了你,没有事情的时候,秒秒钟拿出去顶锅,开除。









    展开全文
  • 1.对象的、软、弱和虚引用 在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无法再使用这个对象。也就是说,只有对象处于可触及(reachable)状态,程序才能使用它。从JDK 1.2版本开始,把对象的...

    转自:http://www.apkbus.com/android-13534-1-1.html

    1.对象的强、软、弱和虚引用
    在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无法再使用这个对象。也就是说,只有对象处于可触及(reachable)状态,程序才能使用它。从JDK 1.2版本开始,把对象的引用分为4种级别,从而使程序能更加灵活地控制对象的生命周期。这4种级别由高到低依次为:强引用、软引用、弱引用和虚引用。图1为对象应用类层次。
     

    图1
    ⑴强引用(StrongReference)
    强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。

    ⑵软引用(SoftReference)
    如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存(下文给出示例)。
    软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。

    ⑶弱引用(WeakReference)
    弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。
    弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。

    ⑷虚引用(PhantomReference)
    “虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。
    虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之 关联的引用队列中。
    ReferenceQueue queue = new ReferenceQueue (); 
    PhantomReference pr = new PhantomReference (object, queue); 
    程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。

    2.对象可及性的判断
        在很多时候,一个对象并不是从根集直接引用的,而是一个对象被其他对象引用,甚至同时被几个对象所引用,从而构成一个以根集为顶的树形结构。如图2所示
        

        在这个树形的引用链中,箭头的方向代表了引用的方向,所指向的对象是被引用对象。由图可以看出,从根集到一个对象可以由很多条路径。比如到达对象5的路径就有①-⑤,③-⑦两条路径。由此带来了一个问题,那就是某个对象的可及性如何判断:
    ◆单条引用路径可及性判断:在这条路径中,最弱的一个引用决定对象的可及性。
    ◆多条引用路径可及性判断:几条路径中,最强的一条的引用决定对象的可及性。
        比如,我们假设图2中引用①和③为强引用,⑤为软引用,⑦为弱引用,对于对象5按照这两个判断原则,路径①-⑤取最弱的引用⑤,因此该路径对对象5的引用为软引用。同样,③-⑦为弱引用。在这两条路径之间取最强的引用,于是对象5是一个软可及对象。

    3.使用软引用构建敏感数据的缓存
    3.1 为什么需要使用软引用
       首先,我们看一个雇员信息查询系统的实例。我们将使用一个Java语言实现的雇员信息查询系统查询存储在磁盘文件或者数据库中的雇员人事档案信息。作为一个用户,我们完全有可能需要回头去查看几分钟甚至几秒钟前查看过的雇员档案信息(同样,我们在浏览WEB页面的时候也经常会使用“后退”按钮)。这时我们通常会有两种程序实现方式:一种是把过去查看过的雇员信息保存在内存中,每一个存储了雇员档案信息的Java对象的生命周期贯穿整个应用程序始终;另一种是当用户开始查看其他雇员的档案信息的时候,把存储了当前所查看的雇员档案信息的Java对象结束引用,使得垃圾收集线程可以回收其所占用的内存空间,当用户再次需要浏览该雇员的档案信息的时候,重新构建该雇员的信息。很显然,第一种实现方法将造成大量的内存浪费,而第二种实现的缺陷在于即使垃圾收集线程还没有进行垃圾收集,包含雇员档案信息的对象仍然完好地保存在内存中,应用程序也要重新构建一个对象。我们知道,访问磁盘文件、访问网络资源、查询数据库等操作都是影响应用程序执行性能的重要因素,如果能重新获取那些尚未被回收的Java对象的引用,必将减少不必要的访问,大大提高程序的运行速度。

    3.2 如果使用软引用
    SoftReference的特点是它的一个实例保存对一个Java对象的软引用,该软引用的存在不妨碍垃圾收集线程对该Java对象的回收。也就是说,一旦SoftReference保存了对一个Java对象的软引用后,在垃圾线程对这个Java对象回收前,SoftReference类所提供的get()方法返回Java对象的强引用。另外,一旦垃圾线程回收该Java对象之后,get()方法将返回null。
    看下面代码:
    MyObject aRef = new  MyObject(); 
    SoftReference aSoftRef=new SoftReference(aRef); 
        此时,对于这个MyObject对象,有两个引用路径,一个是来自SoftReference对象的软引用,一个来自变量aReference的强引用,所以这个MyObject对象是强可及对象。
    随即,我们可以结束aReference对这个MyObject实例的强引用:
    aRef = null; 
    此后,这个MyObject对象成为了软可及对象。如果垃圾收集线程进行内存垃圾收集,并不会因为有一个SoftReference对该对象的引用而始终保留该对象。Java虚拟机的垃圾收集线程对软可及对象和其他一般Java对象进行了区别对待:软可及对象的清理是由垃圾收集线程根据其特定算法按照内存需求决定的。也就是说,垃圾收集线程会在虚拟机抛出OutOfMemoryError之前回收软可及对象,而且虚拟机会尽可能优先回收长时间闲置不用的软可及对象,对那些刚刚构建的或刚刚使用过的“新”软可反对象会被虚拟机尽可能保留。在回收这些对象之前,我们可以通过:
    MyObject anotherRef=(MyObject)aSoftRef.get(); 
        重新获得对该实例的强引用。而回收之后,调用get()方法就只能得到null了。

    3.3 使用ReferenceQueue清除失去了软引用对象的SoftReference
    作为一个Java对象,SoftReference对象除了具有保存软引用的特殊性之外,也具有Java对象的一般性。所以,当软可及对象被回收之后,虽然这个SoftReference对象的get()方法返回null,但这个SoftReference对象已经不再具有存在的价值,需要一个适当的清除机制,避免大量SoftReference对象带来的内存泄漏。在java.lang.ref包里还提供了ReferenceQueue。如果在创建SoftReference对象的时候,使用了一个ReferenceQueue对象作为参数提供给SoftReference的构造方法,如:
    ReferenceQueue queue = new  ReferenceQueue(); 
    SoftReference  ref=new  SoftReference(aMyObject, queue); 
        那么当这个SoftReference所软引用的aMyOhject被垃圾收集器回收的同时,ref所强引用的SoftReference对象被列入ReferenceQueue。也就是说,ReferenceQueue中保存的对象是Reference对象,而且是已经失去了它所软引用的对象的Reference对象。另外从ReferenceQueue这个名字也可以看出,它是一个队列,当我们调用它的poll()方法的时候,如果这个队列中不是空队列,那么将返回队列前面的那个Reference对象。
    在任何时候,我们都可以调用ReferenceQueue的poll()方法来检查是否有它所关心的非强可及对象被回收。如果队列为空,将返回一个null,否则该方法返回队列中前面的一个Reference对象。利用这个方法,我们可以检查哪个SoftReference所软引用的对象已经被回收。于是我们可以把这些失去所软引用的对象的SoftReference对象清除掉。常用的方式为:
    SoftReference ref = null; 
    while ((ref = (EmployeeRef) q.poll()) != null) { 
        // 清除ref 

    理解了ReferenceQueue的工作机制之后,我们就可以开始构造一个Java对象的高速缓存器了。

    3.4通过软可及对象重获方法实现Java对象的高速缓存
        利用Java2平台垃圾收集机制的特性以及前述的垃圾对象重获方法,我们通过一个雇员信息查询系统的小例子来说明如何构建一种高速缓存器来避免重复构建同一个对象带来的性能损失。我们将一个雇员的档案信息定义为一个Employee类:

    public class Employee { 
        private String id;// 雇员的标识号码 
        private String name;// 雇员姓名 
        private String department;// 该雇员所在部门 
        private String Phone;// 该雇员联系电话 
        private int salary;// 该雇员薪资 
        private String origin;// 该雇员信息的来源 
    
        // 构造方法 
        public Employee(String id) { 
           this.id = id; 
           getDataFromlnfoCenter(); 
        } 
    
        // 到数据库中取得雇员信息 
        private void getDataFromlnfoCenter() { 
           // 和数据库建立连接井查询该雇员的信息,将查询结果赋值 
           // 给name,department,plone,salary等变量 
           // 同时将origin赋值为"From DataBase" 
        }
    ……
    这个Employee类的构造方法中我们可以预见,如果每次需要查询一个雇员的信息。哪怕是几秒中之前刚刚查询过的,都要重新构建一个实例,这是需要消耗很多时间的。下面是一个对Employee对象进行缓存的缓存器的定义:
    import java.lang.ref.ReferenceQueue; 
    import java.lang.ref.SoftReference; 
    import java.util.Hashtable; 
    public class EmployeeCache { 
        static private EmployeeCache cache;// 一个Cache实例 
        private Hashtable<String,EmployeeRef> employeeRefs;// 用于Chche内容的存储 
        private ReferenceQueue<Employee> q;// 垃圾Reference的队列 
    
        // 继承SoftReference,使得每一个实例都具有可识别的标识。 
        // 并且该标识与其在HashMap内的key相同。 
        private class EmployeeRef extends SoftReference<Employee> { 
           private String _key = ""; 
    
           public EmployeeRef(Employee em, ReferenceQueue<Employee> q) { 
               super(em, q); 
               _key = em.getID(); 
           } 
        } 
    
        // 构建一个缓存器实例 
        private EmployeeCache() { 
           employeeRefs = new Hashtable<String,EmployeeRef>(); 
           q = new ReferenceQueue<Employee>(); 
        } 
    
        // 取得缓存器实例 
        public static EmployeeCache getInstance() { 
           if (cache == null) { 
               cache = new EmployeeCache(); 
           } 
           return cache; 
        } 
    
        // 以软引用的方式对一个Employee对象的实例进行引用并保存该引用 
        private void cacheEmployee(Employee em) { 
           cleanCache();// 清除垃圾引用 
           EmployeeRef ref = new EmployeeRef(em, q); 
           employeeRefs.put(em.getID(), ref); 
        } 
    
        // 依据所指定的ID号,重新获取相应Employee对象的实例 
        public Employee getEmployee(String ID) { 
           Employee em = null; 
           // 缓存中是否有该Employee实例的软引用,如果有,从软引用中取得。 
           if (employeeRefs.containsKey(ID)) { 
               EmployeeRef ref = (EmployeeRef) employeeRefs.get(ID); 
               em = (Employee) ref.get(); 
           } 
           // 如果没有软引用,或者从软引用中得到的实例是null,重新构建一个实例, 
           // 并保存对这个新建实例的软引用 
           if (em == null) { 
               em = new Employee(ID); 
               System.out.println("Retrieve From EmployeeInfoCenter. ID=" + ID); 
               this.cacheEmployee(em); 
           } 
           return em; 
        } 
    
        // 清除那些所软引用的Employee对象已经被回收的EmployeeRef对象 
        private void cleanCache() { 
           EmployeeRef ref = null; 
           while ((ref = (EmployeeRef) q.poll()) != null) { 
               employeeRefs.remove(ref._key); 
           } 
        } 
    


    展开全文
  • 1. 强引用 (StrongReference) 强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出 OutOfMemoryError错误,使程序异常终止,也不会靠...
  • Java 强引用,软引用,弱引用

    千次阅读 2014-06-28 14:23:12
    1、强引用 public void handleMessage(Message msg) { case FAIL: GoplayException mException = new GoplayException(); setVideoUrlFailReason(mException); mListener.onFailed(mException); break;
  • Java四种引用包括强引用,软引用,弱引用,虚引用。 Java四种引用包括强引用,软引用,弱引用,虚引用。   强引用: 只要引用存在,垃圾回收器永远不会回收 Object obj = new Object(); //可直接通过...
  • 为了解决内存操作不灵活这个问题,可以采用软引用等方法。    在JDK1.2以前的版本中,当一个对象不被任何变量引用,那么程序就无法再使用这个对象。也就是说,只有对象处于可触及状态,程序才能使用它。这 ...
  • 强引用 弱引用

    2014-07-24 13:48:21
    1.对象的强、软、弱和虚引用 在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无法再使用...这4种级别由高到低依次为:强引用、软引用、弱引用和虚引用。图1为对象应用类层次。 图1 ⑴强引用
  • 1.概念解释强引用是使用最普遍的引用:Object o=new Object(); 特点:不会被GC将对象的引用显示地置为null:o=null; // 帮助垃圾收集器回收此对象举例ArrayList的实现源代码: 软引用用来描述一些还有用但是并非...
  • 强引用:普通的创建对象构造的就是强引用关系,直到对象生命周期结束,或者显示赋值为null,这时候表明对象可以被回收了。 软引用:软引用相对强引用比较弱一些,可以豁免一些jvm的垃圾回收,当jvm认为空间不足时会...
  • 特点:我们平常典型编码 Object obj=new Object() 中的obj就是强引用。通过关键字new创建的对象所关联的引用就是强引用。当JVM内存不足时,JVM宁愿抛出OutofMemoryError运行时错误(OOM),使程序异常终止,也不会.....
  • 强引用 弱引用 软引用

    千次阅读 2014-03-12 15:42:19
    Java之WeakReference与SoftReference使用讲解 ...Java 2 平台引入了 java.lang.ref 包,其中包括的类可以让您引用对象,而不将它们留在内存中。这些类还提供了与垃圾收集器(garbage collector)之间有限的交互。
  • 转载请注明出处:... 1、强引用(StrongReference)    强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。如下: [java] view plaincopyprint?
  • 强引用弱引用软引用

    2014-09-22 21:10:34
     在JDK1.2以前的版本中,当一个对象不被任何变量引用,那么程序就无法再使用这个对象。也就是说,只有对象处于可触及状态,程序才能使用它。这 就像在日常生活中,从商店购买了某样物品后,如果有用,就一直保留它...
  • 为了解决内存操作不灵活这个问题,可以采用软引用等方法。  在JDK1.2以前的版本中,当一个对象不被任何变量引用,那么程序就无法再使用这个对象。也就是说,只有对象处于可触及状态,程序才能使用它。这 就像在...
  • 1 强引用 特点:我们平常典型编码Object obj = new Object()中的obj就是强引用。通过关键字new创建的对象所关联的引用就是强引用。 当JVM内存空间不足,JVM宁愿抛出OutOfMemoryError运行时错误(OOM),使程序异常...
  • 只要强引用还存在 垃圾回收器永远不会回收被强引用 引用的对象 如果强引用为null 或者已经超过了引用的作用范围对象就会被回收 2.软引用 如果当前对象没有强引用引用 在垃圾回收后的内存不够了 就会回收软引用连接...
  • 背景:收到公众投稿,《从面试题中看Java的Reference(引用)》,分析的很不错,总感觉少了实际的例子和应用场景。于是结合自己工作中场景,小总结一下。...1、强引用 2、软引用 3、弱引用 4、什么时候用软引用及弱引用
  • 强引用,软引用,弱引用,幻象引用有什么区别? 不同的引用类型,主要体现的是对象的不同的可达性(reachable)状态和对垃圾收集的影响。 所谓强引用 (Strong Reference) 就是我们常见的普通对象引用,只要还有...
  • 在周志明前辈的《深入理解Java虚拟机(第二版)》3.2.3节:再谈引用 中,介绍了Java中的几种引用: 在JDK 1.2以前,Java中的引用的定义很传统:如果reference类型的数据中存储的数值代表的是另外一块内存的起始地址...
  • 1、强引用(StrongReference)    强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。如下: [java] view plain copy Object o=new Object(); //...
  • 因为软引用、弱引用、虚引用,不会和它关联的对象造成引用,所以不会对和他们关联的对象的生命周期产生影响。特别注意,在世纪程序设计中一般很少使用弱引用与虚引用,使用软用的情况较多,这是因为软引用可以加速...
  • Java中的强引用和弱引用
  • 1,强引用: package com.myjava.reference; /**  * ①强引用不会被垃圾回收器自动回收  * ②当内存空间不足时,Java虚拟机宁可抛出OutOfMemoryError错误,也不会随意回收强引用对象来解决内存不足问题  * @...
  • 我属于自学型的,所以知识不够系统,只能是一边儿工作一边查漏补缺,在此要对那些写技术文章的人由衷的说句谢谢,谢谢各位大神们的分享 1,强引用,看好多文章喜欢x

空空如也

1 2 3 4 5 ... 20
收藏数 12,032
精华内容 4,812
关键字:

强引用