1、Java中四种引用类型:强软弱虚
面试:强引用和弱引用的区别?
1.1 强引用
普通变量赋值即为强引用,如 A a = new A();
强引用的回收特点:
当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠回收具有强引用的对象,来解决内存不足的问题。通过 GC Root 的引用链,如果强引用不到该对象,该对象才能被回收。
如果想中断或者回收强引用对象可以显式地将引用赋值为null(a=null),这样的话JVM就会在合适的时间,进行垃圾回收。
1.2. 软引用(SoftReference)
“内存不够就回收,内存充足不回收”
“适合做缓存”
1、例如:SoftReference a = new SoftReference(new A());引用和对象通过SoftReference建立关联
2、当系统内存够用就保留不回收(及时发生了GC),内存不足时,会被回收
3、软引用自身不会被垃圾回收,因为GC Root还引用着,软引用自身需要配合引用队列来释放。
软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。
4、软引用适合缓存使用的场景,当内存不够的时候,对象是被回收的。
1.3. SoftReference实现Cache(例子)
SoftReference是强引用,它保存的对象实例,除非JVM即将OutOfMemory,否则不会被GC回收。这个特性使得它特别适合设计对象Cache。对于Cache,我们希望被缓存的对象最好始终常驻内存,但是如果JVM内存吃紧,为了不发生OutOfMemoryError导致系统崩溃,必要的时候也允许JVM回收Cache的内存,待后续合适的时机再把数据重新Load到Cache中。这样可以系统设计得更具弹性。
实例:软引用在设备内存比较少的时候特别有用,比如Android系统。
一个android应用如果设计到通过网络获取图片,为了让系统更快的运行和更节省流量我们可以将已经下载下来的图片在内存中缓存起来,当第二次浏览到该图片时就可以从缓存中拿,如果没有再去加载下载的文件。
安卓里面,listView里面存一张图片和一些文字描述,这些图片要去网络上加载解析渲染后放到内存,非常消耗内存。
问题:
1、 如果每次读取图片都从硬盘读取则会严重影响性能
2、 如果一次性全部加载到内存中又可能造成内存溢出
此时使用软引用可以解决这个问题。
设计思路:用一个HashMap来保存图片的路径和相应图片对象关联的软引用之间的映射关系,在内存不足时JVM会自动回收这些缓存图片对象所占用的空间,从而有效地避免了OOM的问题
JSONRuslt [{ ‘image’:’http://qiniu/222.jpg’,‘name’:’Iphone13’,‘price’: 22323}]List list;Android里面控件:ListView展示列表
public class ImageLoader { //强引用,内存不足时候,里面的Bitmap也不会销毁 private Map cacheImage = new HashMap(); //弱引用:内存不足会销毁,下次找不到Bitmap就去硬盘找 private Map<String,SoftReference> cacheImage = new HashMap<String,SoftReference>(); public void loadImage(final String path,final Callback callback){ SoftReference softReference = cacheImage.get(path); // 内存的map中有这个Bitmap if(softReference!=null){ Bitmap bm = softReference.get(); if(bm!=null){ callback.execute(bm); return; } } // 改进:内存中没有,先去硬盘判断有没有下载 // 如果硬盘上有:直接加载硬盘上的 // 如果硬盘上没有:再去网络下载 // 内存的map中没有这个Bitmap new Thread(new Runnable() { public void run() { HttpClient client = new DefaultHttpClient(); try { HttpResponse response = client.execute(new HttpGet(path)); HttpEntity entity = response.getEntity(); byte []bs= EntityUtils.toByteArray(entity); final Bitmap bm = BitmapFactory.decodeByteArray(bs, 0,bs.length); SoftReference reference = new SoftReference(bm); cacheImage.put(path,reference); callback.execute(bm); entity.consumeContent(); // 改进:下载完之后保存到硬盘 } catch (Exception e) { e.printStackTrace(); } } }).start(); } public static abstract class Callback{ abstract void execute(Bitmap bm); }}
1.4. 弱引用(WeakReference)
“只要发生GC,一定被回收”
1、例如:WeakReference a = new WeakReference(new A());
2、如果仅有弱引用引用该对象时,只要发生垃圾回收,就会释放该对象
3、当一个对象仅仅被weak reference指向, 而没有任何其他strong reference指向的时候, 如果GC运行, 那么这个对象就会被回收。如果存在强引用同时与之关联,则进行垃圾回收时也不会回收该对象。
4、ThreadLocal和WeakHashMap内部都是使用了弱引用,用来保证那些不被用到的key值,在垃圾回收的时候可以被回收掉。
1.1.5. 虚引用(PhantomReference)
1、 例如: PhantomReference a = new PhantomReference(new A(), referenceQueue);
2、 也称为幽灵引用或者幻影引用,它是最弱的引用关系。无法通过虚引用来取得一个对象实例。为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。PhantomReference类来实现虚引用。
2、必须配合引用队列一起使用,当虚引用所引用的对象被回收时(a对象、b对象),由 Reference Handler 线程将虚引用对象入队,这样就可以知道哪些对象被回收,从而对它们关联的资源做进一步处理
引用总结
1、对于强引用,平时在编写代码时会经常使用。
2、而其他三种类型的引用,使用得最多就是软引用和弱引用,这两种既有相似之处又有区别,他们都来描述非必须对象。
3、被软引用关联的对象只有在内存不足时才会被回收,而被弱引用关联的对象在JVM进行垃圾回收时总会被回收。
4、Java中4种引用的级别由高到低依次为:强引用 > 软引用 > 弱引用 > 虚引用