强引用:(StrongReference)
强引用指普通的对象引用
例如:
StringBuffer str = new StringBuffer("hello world");
局部变量str会被放到栈里,而StringBuffer实例对象会被放在堆内,局部变量str指向堆内的StringBuffer对象,通过str可以操作该对象,那么str就是StringBuffer的强引用
StringBuffer str1 = str;
当发生了这条语句,则
此时这两个引用都是强引用
强引用具备如下特点:
1、通过强引用可以直接访问目标对象
2、强引用所指向的对象在任何时候都不会被系统回收,虚拟机宁愿抛出OOM(内存溢出)异常,也不会回收强引用所指向的对象
3、强引用可能导致内存泄漏(站着空间不释放,积累的多了内存泄漏会导致内存溢出)
jvm也不会靠随意回收具有强引用的对象来解决内存不足的问题。如果不使用时,要通过如下方式来弱化引用,如下: o=null; // 帮助垃圾收集器回收此对象 显式地设置o为null,或超出对象的生命周期范围,则gc认为该对象不存在引用,这时就可以回收这个对象。具体什么时候收集这要取决于gc的算法。 举例: public void test(){ Object o=new Object(); } 在一个方法的内部有一个强引用,这个引用保存在栈中,而真正的引用内容(Object)保存在堆中。当这个方法运行完成后就会退出方法栈,则引用内容的引用不存在,这个Object会被回收。但是如果这个o是全局的变量时,就需要在不用这个对象时赋值为null,因为强引用不会被垃圾回收。
软引用:(SoftReference)
软引用描述一些还有用但非必需的对象,用java.lang.ref.SoftReference类表示,对于软引用关联的对象GC未必会一定会收,只有当内存资源紧张时,软引用对象才会被回收,所以软引用对象不会引起内存溢出(OOM)
1 import java.lang.ref.SoftReference; 2 3 //软引用问题 4 public class SoftRef { 5 public static class User{ 6 public int id; 7 public String name; 8 public User(int id,String name) { 9 this.id = id; 10 this.name = name; 11 } 12 @Override 13 public String toString() { 14 return "User [id=" + id + ", name=" + name + "]"; 15 } 16 17 18 } 19 20 public static void main(String[] args) { 21 User u = new User(1,"吉米"); 22 //从强引用中获取软引用 23 SoftReference<User> sr = new SoftReference<User>(u); 24 //将强引用去除 25 u = null; 26 // get方法返回此引用对象的指示对象。用来获取与软引用关联的对象的引用 27 System.out.println(sr.get()); 28 System.out.println("After GC"); 29 System.gc(); 30 System.out.println(sr.get()); 31 32 33 //这样测试出来,软引用可能不会被gc回收,此时需要模拟一下内存很紧张的状态 34 byte b[] = new byte[1024*925*77]; 35 System.gc(); 36 System.out.println(sr.get()); 37 38 } 39 }
输出:在-Xmx10m下输出
User [id=1, name=吉米] //第一次从软引用中获取数据 After GC User [id=1, name=吉米] //GC没有清除软引用 null //由于内存紧张,软引用被GC清理
此外,软引用还可以附带一个引用队列,当对象可达性发生改时(由可达变为不可达,被回收),此时软引用进入队列,通过这个引用队列,可以跟踪对象的回收情况
弱引用:(WeakReference)
弱引用是比软引用还弱的引用,在系统进行GC 时,只要发现弱引用,不管系统的堆空间是用了一点还是用了一大半,都会回收弱引用的对象。但是通常GC线程的优先级较低,因此不能立即发现持有弱引用的对象,在这种情况下弱引用对象可以存在较长的时间,一旦弱引用对象被回收,弱引用对象会加到一个注册的引用队列中去
弱引用代码:
1 import java.lang.ref.WeakReference; 2 3 //弱引用 4 public class WeakRef { 5 public static class User{ 6 public int id; 7 public String name; 8 public User(int id, String name) { 9 this.id = id; 10 this.name = name; 11 } 12 @Override 13 public String toString() { 14 return "[id=" + id + ", name=" + name + "]"; 15 } 16 17 } 18 19 public static void main(String[] args) { 20 User u = new User(1,"geym"); 21 //创建软引用对象 22 WeakReference<User> wr = new WeakReference<User>(u); 23 System.out.println(wr.get()); 24 System.gc(); 25 System.out.println("After GC:"); 26 System.out.println(wr.get()); 27 } 28 }
输出:
[id=1, name=geym] After GC: null
根据软引用和弱引用的特性,非常适合保存一些可有可无的缓存,如果这么做,当系统内存空间不足时,会及时回收他们,不会导致内存溢出,当系统内存资源充足时,这些还存有可以存在相当长的时间,提升系统速度。
虚引用:(PhantomReference)(对象回收和跟踪)
虚引用是所有引用中最弱的一个持有一个虚引用的对象,和没有引用一样,随时都有可能会被垃圾回收器回收,当用虚引用的get方法去尝试获得强引用对象时总是会失败,并且他必须和引用队列一起使用,用于跟踪垃圾回收过程,当垃圾回收器回收一个持有虚引用的对象时,在回收对象后,将这个虚引用对象加入到引用队列中,用来通知应用程序垃圾的回收情况。
虚引用代码:
1 import java.lang.ref.PhantomReference; 2 import java.lang.ref.ReferenceQueue; 3 4 public class PlantomRef { 5 public static class User{ 6 public int id; 7 public String name; 8 public User(int id,String name){ 9 this.id = id; 10 this.name = name; 11 } 12 @Override 13 public String toString() { 14 return "User [id=" + id + ", name=" + name + "]"; 15 } 16 17 } 18 19 public static void main(String[] args) { 20 User u = new User(1,"吉米"); 21 ReferenceQueue<? super User> queue = new ReferenceQueue<User>(); 22 PhantomReference<User> pr = new PhantomReference<User>(u,queue); 23 System.out.println(pr.get()); 24 25 } 26 27 28 29 }
输出为null
由于虚引用可以跟踪对象的回收时间,所以可以将一些资源的释放操作放置在虚引用中执行和记录
引用类型 被垃圾回收时间 用途 生存时间
强引用 从来不会 对象的一般状态 JVM停止运行时终止
软引用 当内存不足时 对象缓存 内存不足时终止
弱引用 正常垃圾回收时 对象缓存 垃圾回收后终止
虚引用 正常垃圾回收时 跟踪对象的垃圾回收 垃圾回收后终止