vlambda博客
学习文章列表

Java对象的四种引用类型

Java对象的引用包括:强引用,软引用,弱引用,虚引用

作用:

  • 可以让程序员通过代码的方式决定某些对象的生命周期

  • 有利于JVM进行垃圾回收

1.强引用(StrongReference

概念:强引用是指创建一个对象并它赋值给一个引用,引用是存在JVM中的栈中的

private static void testStrongReference() { Object object = new Object(); Object[] objects = new Object[1000];}

只要有引用变量指向它们的时候,它们将不会被垃圾回收,如果想中断强引用和某个对象之间的关联,可以显示地将引用赋值为null,这样一来的话,JVM在合适的时间就会回收该对象

public synchronized void removeAllElements() { modCount++; for (int i = 0; i < elementCount; i++) elementData[i] = null;  elementCount = 0;}

2.软引用(SoftReference

概念:如果一个对象具有软引用,只要内存空间足够,垃圾回收器就不会回收它。如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。这个引用指向堆中的一个具体object ,在堆中空间不够的时候而且gc 引用发现这个具体object 只有这个软引用指向他 就也会对这个object 发起回收(存在强引用的Object不会被回收,但是软引用的会被回收

用途:软引用可用来实现内存敏感的高速缓存,比如网页缓存、图片缓存等。使用软引用能防止内存泄露,增强程序的健壮性。   

public class ImageMemoryCache { /** * 从内存读取数据速度是最快的,为了更大限度使用内存,这里使用了两层缓存。硬引用缓存不会轻易被回收,用来保存常用数据,不常用的转入软引用缓存。*/ private static final int SOFT_CACHE_SIZE = 20; // 软引用缓存容量 private static LruCache<String, Bitmap> mLruCache; // 硬引用缓存 private static LinkedHashMap<String, SoftReference<Bitmap>> mSoftCache; // 软引用缓存  public ImageMemoryCache(Context context) { int memClass = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass(); int cacheSize = 1024 * 1024 * memClass / 4; // 硬引用缓存容量,为系统可用内存的1/4 mLruCache = new LruCache<String, Bitmap>(cacheSize) { @Override protected int sizeOf(String key, Bitmap value) { if (value != null) return value.getRowBytes() * value.getHeight(); else return 0; }  @Override protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) { if (oldValue != null) // 硬引用缓存容量满的时候,会根据LRU算法把最近没有被使用的图片转入此软引用缓存 mSoftCache.put(key, new SoftReference<Bitmap>(oldValue)); } }; mSoftCache = new LinkedHashMap<String, SoftReference<Bitmap>>(SOFT_CACHE_SIZE, 0.75f, true) { private static final long serialVersionUID = 6040103833179403725L;  @Override protected boolean removeEldestEntry(Entry<String, SoftReference<Bitmap>> eldest) { if (size() > SOFT_CACHE_SIZE) { return true; } return false; } }; }  /** * 从缓存中获取图片 */ public Bitmap getBitmapFromCache(String url) { Bitmap bitmap; // 先从硬引用缓存中获取 synchronized (mLruCache) { bitmap = mLruCache.get(url); if (bitmap != null) { // 如果找到的话,把元素移到LinkedHashMap的最前面,从而保证在LRU算法中是最后被删除 mLruCache.remove(url); mLruCache.put(url, bitmap); return bitmap; } } // 如果硬引用缓存中找不到,到软引用缓存中找 synchronized (mSoftCache) { SoftReference<Bitmap> bitmapReference = mSoftCache.get(url); if (bitmapReference != null) { bitmap = bitmapReference.get(); if (bitmap != null) { // 将图片移回硬缓存 mLruCache.put(url, bitmap); mSoftCache.remove(url); return bitmap; } else { mSoftCache.remove(url); } } } return null; }  /** * 添加图片到缓存 */ public void addBitmapToCache(String url, Bitmap bitmap) { if (bitmap != null) { synchronized (mLruCache) { mLruCache.put(url, bitmap); } } }  public void removeBitmap(String url) { if (url != null) { synchronized (mLruCache) { mLruCache.remove(url); } synchronized (mSoftCache) { mSoftCache.remove(url); } } }  public void clearCache() { mSoftCache.clear(); }}

3.弱引用(WeakReference

概念:弱引用也是用来描述非必需对象的,当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象

4.虚引用(PhantomReference

概念:虚引用和前面的软引用、弱引用不同,它并不影响对象的生命周期。如果一个对象与虚引用关联,则跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收;虚引用必须和引用队列关联使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会把这个虚引用加入到与之关联的引用队列中

5.引用队列

ReferenceQueue queue = new ReferenceQueue(); SoftReference ref = new SoftReference(object, queue);

当这个SoftReference所软引用的对象被垃圾收集器回收的同时,ref所强引用的SoftReference对象被列入ReferenceQueue。也就是说,ReferenceQueue中保存的对象是Reference对象,而且是已经失去了它所软引用的对象的Reference对象。

6.Reference

  • Reference主要是负责内存的一个状态,当然它还和java虚拟机,垃圾回收器打交道。Reference类首先把内存分为4种状态:

Active:一般来说内存一开始被分配的状态都是Active

Pending:是指快要被放进队列的对象,也就是马上要回收的对象

Enqueued:就是对象的内存已经被回收了,我们已经把这个对象放入到一个队列中,方便以后我们查询某个对象是否被回收

Inactive:就是最终的状态,不能再变为其它状态

  • 几个变量:

referent:表示其引用的对象,即在构造的时候需要被包装在其中的对象。

queue:是对象即将被回收时所要通知的队列。当对象即将被回收时,整个reference对象,而不仅仅是被回收的对象,会被放到queue里面,然后外部程序即可通过监控这个queue即可拿到相应的数据了。

next:即当前引用节点所存储的下一个即将被处理的节点。但next仅在放到queue中才会有意义,因为只有在enqueue的时候,会将next设置为下一个要处理的Reference对象。为了描述相应的状态值,在放到队列当中后,其queue就不会再引用这个队列了。而是引用一个特殊的 ENQUEUED(内部定义的一个空队列)。因为已经放到队列当中,并且不会再次放到队列当中。

discovered:表示要处理的对象的下一个对象。即可以理解要处理的对象也是一个链表,通过discovered进行排队,这边只需要不停地拿到pending,然后再通过discovered不断地拿到下一个对象赋值给pending即可,直到取到了最有一个。它是被JVM使用的。

pending:是等待被入队的引用列表。JVM收集器会添加引用到这个列表,直到Reference-handler线程移除了它们。这个列表使用discovered 字段来连接它下一个元素(即 pending 的下一个元素就是discovered对象。r = pending; pending = r.discovered)。