1.强引用(Reference,默认支持模式)
1.1.简介
1>.当内存不足时,JVM开始垃圾回收,对于强引用的对象,就算出现了OOM也不会对该对象进行垃圾回收,死都不回收
2>.强引用是我们最常见的普通对象引用,只要还有强引用指向一个对象,就能表明对象还"活着",垃圾收集器就不会碰这种对象.在java中最常见的就是强引用,把一个对象赋给一个引用变量(如:Object object=new Object),这个引用变量就是一个强引用,当一个对象被强引用变量引用时,他处于"可达"状态,他是不可能被垃圾回收机制回收的,即使该对象以后永远都不会被用到,JVM也不会回收.因此强引用是造成java内存泄露的主要原因之一
3>.对于一个普通的对象,如果没有其他的引用关系,只要超过了引用的作用域或者显示地将相应(强)引用(变量)赋值为null,一般认为该对象可以被当作垃圾回收了(当然具体的回收时机还是要看垃圾收集策略)
1.2.代码示例
public class JVMTest {
public static void main(String[] args) {
//object强引用
Object object1 = new Object();
//object1,object2两个引用指向相同的对象
Object object2 = object1;
//将object1引用赋值为null;
object1 = null;
//启动gc,但是不会马上gc
System.gc();
//object2引用还是正常的,引用Object对象除了object1这个引用,还有object2这个引用
//object1引用赋值为null,但是object2还在正常引用者着,对象还是"可达"状态
//所以jvm不会对该对象进行垃圾回收
System.out.println(object2); //java.lang.Object@1540e19d
}
}
2.软引用(SoftReference)
2.1.简介
1>.软引用是一种相对强引用弱化了一些的引用,需要用java.lang.ref.Softreference类来实现,可以让对象豁免一些垃圾收集
2>.对于只有软引用的对象来说:
①.当系统内存充足时他不会被回收;
②.当系统内存不足时他会被回收;
2.2.代码示例
public class JVMTest {
public static void main(String[] args) {
//softRef_memory_enough();
softRef_memory_notenough();
}
//内存不够用,软引用变量引用的对象会被回收
//内存配置: -Xms5m -Xmx5m
public static void softRef_memory_notenough() {
Object object1 = new Object();
SoftReference<Object> softReference = new SoftReference<Object>(object1);
System.out.println(object1); //java.lang.Object@1540e19d
System.out.println(softReference.get()); //java.lang.Object@1540e19d
//强引用变量赋值为null,此时对象只有软引用
object1 = null;
//手动触发垃圾回收
System.gc();
try {
//故意产生大对象,导致出现OOM,查看软引用的回收情况
//此时手动将内存配置为5M,创建了一个10M的大对象,导致内存溢出
byte[] bytes = new byte[10 * 1024 * 1024];
} catch (Exception e) {
e.printStackTrace(); //java.lang.OutOfMemoryError: Java heap space
} finally {
System.out.println(object1); //null
//内存不够用,软引用对象中引用的那个对象会被gc
System.out.println(softReference.get()); //null
}
}
//内存够用,软引用对象中引用的对象不会被回收
public static void softRef_memory_enough() {
//强引用
Object object1 = new Object();
//软引用
SoftReference<Object> softReference = new SoftReference<Object>(object1);
//两个引用变量指向同一个对象
System.out.println(object1); //java.lang.Object@1540e19d
System.out.println(softReference.get()); //java.lang.Object@1540e19d
//强引用变量赋值为null
object1 = null;
//手动触发垃圾回收
System.gc();
System.out.println(object1); //null
//由于系统内存充足,软引用对象中引用的那个对象不会被回收
//软引用对象本身也不会被回收
System.out.println(softReference.get()); //java.lang.Object@1540e19d
}
}
3.弱引用(WeakReference)
3.1.简介
1>.弱引用需要用java.lang.ref.WeakReference类来实现,他比软引用的生存期更短
2>.对于只有弱引用的对象来说,只要垃圾回收机制一运行,不管JVM的内存空间是否足够,都会回收该对象占用的内存
3.2.代码示例
public class JVMTest {
public static void main(String[] args) {
//强引用
Object object1=new Object();
//弱引用
WeakReference<Object> weakReference=new WeakReference<Object>(object1);
System.out.println(object1); //java.lang.Object@1540e19d
System.out.println(weakReference.get()); //java.lang.Object@1540e19d
//强引用赋值为null
object1=null;
//手动触发gc
System.gc();
System.out.println("----------");
//gc运行,无论jvm内存空间是否足够,弱引用对象中引用的那个对象都会被回收
System.out.println(object1); //null
System.out.println(weakReference.get()); //null
}
}
4.虚引用(Phantomreference)
4.1.简介
1>.虚引用需要使用java.lang.ref.Phantomreference类来实现
2>.顾名思义,虚引用就是形同虚设,与其他几种引用不同,虚引用并不会决定对象的生命周期,如果一个对象仅持有虚引用,那么他就和没有任何引用一样,在任何时候都有可能被垃圾回收器回收;
他不能单独使用,也不能通过它访问对象,虚引用必须和引用队列(ReferenceQueue)联合使用,当关联的引用队列中有数据时,意味着引用对象中指向的堆内存中的对象被回收,通过这种方式,JVM允许我们在对象销毁之后做一些我们自己想做的事情
3>.虚引用的主要作用就是跟踪对象被垃圾回收的状态
,他只提供了一种确保对象被finalize以后做某些事情的机制
4>.PhantomReference的get()方法总是返回null,因此无法访问对应的引用对象,他的意义在于说明一个对象已经进入了finalization阶段,可以被gc回收,用来实现比finalization机制更加灵活的回收操作
5>.设置虚引用关联的唯一目的就是在这个对象被垃圾收集器回收的时候收到一个系统通知或者后续添加进一步的处理
6>.java技术允许使用finalize()方法在垃圾收集器将对象从内存中清除出去之前做一些必要的清理工作
4.2.代码示例
public class JVMTest {
public static void main(String[] args) {
Object object1 = new Object();
ReferenceQueue<Object> queue=new ReferenceQueue<Object>();
//虚引用就相当于没有引用
PhantomReference<Object> phantomReference=new PhantomReference<Object>(object1,queue);
System.out.println(object1); //java.lang.Object@1540e19d
System.out.println(phantomReference.get()); //null
System.out.println(queue.poll()); //null
object1=null;
System.gc();
System.out.println("----------------");
//对象被gc回收之后,对象所在的那个虚引用对象会被保存在queue中
System.out.println(object1); //null
System.out.println(phantomReference.get()); //null
System.out.println(queue.poll()); //java.lang.ref.PhantomReference@677327b6
}
}
5.引用队列(ReferenceQueue)
5.1.简介
某个对象在被回收之后,其相应的包装类,即ref对象会被放入queue中;或者说,当关联的引用队列中有数据时,意味着引用对象中指向的堆内存中的对象被回收,通过这种方式,JVM允许我们在对象销毁之后做一些我们自己想做的事情
5.2.代码示例
public class JVMTest {
public static void main(String[] args) {
Object object1 = new Object();
ReferenceQueue<Object> queue=new ReferenceQueue<Object>();
WeakReference<Object> weakReference=new WeakReference<Object>(object1,queue);
System.out.println(object1); //java.lang.Object@1540e19d
System.out.println(weakReference.get()); //java.lang.Object@1540e19d
//由于对象并没有被gc,所以引用对象没有被添加到queue中
System.out.println(queue.poll()); //null
System.out.println("========================");
object1=null;
System.gc();
System.out.println(object1); //null
System.out.println(weakReference.get()); //null
//弱引用对象中引用的那个对象被gc之后,引用对象会被保存到queue中
System.out.println(queue.poll()); //java.lang.ref.WeakReference@677327b6
}
}
6.软引用和弱引用的使用场景
1>.需求:
假如有一个应用需要读取大量的本地图片,如果每次都要从硬盘读取图片则会严重影响性能;如果一次性全部读取到内存中又可能会造成内存溢出
2>.设计思路:
使用一个hashMap来保存图片的路径和相应的图片对象的软引用的关联关系,在内存不足时,jvm会自动回收这些缓存图片对象所占的空间,从而有效的避免OOM
3>.代码实现:
Map<String,softReference<Bitmap>> imageCache = new HashMap<String,softReference<Bitmap>>();
7.WeakHashMap
7.1.简介
1>.WeakHashMap继承于AbstractMap,实现了Map接口.和HashMap一样,WeakHashMap也是一个散列表,它存储的内容也是键值对(key-value)映射,而且键和值都可以是null
2>.WeakHashMap的键是"弱键".在 WeakHashMap中,当某个键不再正常使用时,它对应的键值对也就从WeakHashMap中被自动移除
3>.这个"弱键"的原理呢?
大致上就是,通过WeakReference和ReferenceQueue实现的. WeakHashMap的key是"弱键",即是WeakReference类型的;ReferenceQueue是一个队列;它会保存被GC回收的"弱键".实现步骤是:
①.新建WeakHashMap,将"键值对"添加到WeakHashMap中;
实际上,WeakHashMap是通过数组table保存Entry(键值对),每一个Entry实际上是一个单向链表,即Entry是键值对链表;
②.当某"弱键"不再被其它对象引用(即key=null),并被GC回收时.在GC回收该"弱键"(对象)时,这个"弱键"也同时会被添加到ReferenceQueue(key)队列中;
③.当下一次我们需要操作WeakHashMap时,会先同步table和queue,table中保存了全部的键值对,而queue中保存被GC回收的"弱键";同步它们,就是删除table中被GC回收的那些"弱键"对应的键值对
4>."弱键"是一个"弱引用(WeakReference)",
在Java中,WeakReference和ReferenceQueue 是联合使用的.在WeakHashMap中亦是如此;如果弱引用所引用的对象被垃圾回收(key=null),Java虚拟机就会把这个弱引用加入到与之关联的引用队列中;接着,WeakHashMap会根据"引用队列"来删除’已被GC回收的弱键’对应的那些键值对
7.2.代码示例
public class JVMTest {
public static void main(String[] args) {
//和HashMap一样,WeakHashMap也是一个散列表,它存储的内容也是键值对(key-value)映射,而且键和值都可以是null
//不过WeakHashMap的键是“弱键”.在 WeakHashMap中,当某个键不再正常使用时,会从WeakHashMap中被自动移除
WeakHashMap<String, Object> weakHashMap = new WeakHashMap<String, Object>();
//强引用
String key = new String("aa");
String value = new String("hello world");
//将两个强引用变量组装成一个node<key,value>对象,赋值给弱引用变量weakHashMap
//此时内存中有三个对象
weakHashMap.put(key, value);
System.out.println(weakHashMap); //{aa=hello world}
//强引用变量赋值为null
key = null;
//手动触发GC
//如果弱引用(key)所引用的对象被垃圾回收(key=null),Java虚拟机就会把这个弱引用加入到与之关联的引用队列中;
//接着,WeakHashMap会根据"引用队列"中'已被GC回收的弱键'来删除对应的那些键值对
System.gc();
System.out.println(weakHashMap);
}
}