文章导读:
从JDK1.2版本开始,把对象的引用分为四种级别,从而使程序能更加灵活的控制对象的生命周期。这四种级别由高到低依次为:强引用、软引用、弱引用和虚引用, 本章内容介绍了Reference的概念和语法实现. 附件有源码下载
视频与源码下载:http://edu.51cto.com/lecturer/index/user_id-9166337.html (代码在视频的附件中)
强引用(StrongReference) :
强引用是使用最普遍的引用. 如果一个对象具有强引用, 那垃圾回收器绝不会回收它,当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止, 也不会靠随意回收具有强引用的对象来解决内存不足的问题
1 public class RefDemo { 2 3 // 强引用, JVM -Xms5M -Xmx10M 4 public static void demo01(){ 5 // 强引用,即使内存溢出,垃圾回收也不会回收此对象 6 byte[] b = new byte[1024*1024*10]; // 默认创建10MB的byte数组 7 } 8 }
为了方便测试首先要在JVM中配堆内存大小如图所示:
我们声明的 byte[] b = new byte[1024*1024*10] 是强引用类型,及时内存溢出GC也不会回收强引用的对象, 因此会抛出堆内存溢出
软引用(SoftReference):
软引用是除了强引用外, 最强的引用类型. 可以通过SoftReference使用软引用. 一个持有软引用的对象,不会被JVM很快回收. JVM会根据当前堆的使用情况来判断何时回收. 当堆的使用率接近临界点时, 才会去回收软引用的对象. 只要有足够的内存, 软引用变可以在内存中存货很长时间.因此, 软引用可以用于实现对内存敏感的cache
1 // 软引用: 内存不够才会被回收,项目中的缓存 2 public static void demo02(){ 3 MyObject myO=new MyObject(); 4 // 采用软引用存储 5 SoftReference<MyObject> softRef=new SoftReference<MyObject>(myO); 6 myO = null; //强引用已经失效 7 // 手动调用垃圾回收,一般JVM自动调用 8 System.out.println(softRef.get()); 9 System.gc(); // 如果内存足够,软引用是不会被回收的 10 System.out.println(softRef.get()); 11 // 不断的填充堆空间,如果内存不够则回收 12 List<Object> oList=new ArrayList<Object>(); 13 for(int i=1;i<=10;i++){ 14 // 每次填充1MB 15 oList.add(new byte[1024*1024*1]); 16 System.out.println("当前虚拟机中的内存总量" + Runtime.getRuntime().totalMemory()/1024.00/1024 + "MB"); 17 System.out.println("i:" + i); 18 // 软引用: 内存不够才会被回收 19 System.gc(); 20 } 21 }
从运行结果我们可以看出, GC在内存不充足的时候才会回收软引用的空间. 但是回收的空间也不足以存储生成的数组对象,因此还是抛出了堆内存溢出
弱引用 (WeakReference):
弱引用是一种比软引用较弱的引用类型, 在系统GC时, 只要发现弱引用, 不管系统堆空间是否足够, 都会将对象进行回收. 但是由于垃圾回收器的线程通常优先级很低. 因此, 并不一定能很快发现持有的弱引用的对象. 在这种情况下. 弱引用对象可以存在较长时间.
1 public class MyObject { 2 @Override 3 public String toString() { 4 return "I am MyObject"; 5 } 6 @Override 7 protected void finalize() throws Throwable { 8 super.finalize(); 9 System.out.println("MyObject's finalize called"); // 被回收时输出 10 } 11 public static void main(String[] args) throws InterruptedException { 12 MyObject obj = new MyObject(); 13 WeakReference<MyObject> softRef = new WeakReference<MyObject>(obj); // 创建一个引用队列 14 System.gc(); // 因为还有强引用因此不能回收,一般在生产者模式下不会手动调用垃圾回收方法 15 System.out.println("获取弱引用:" + softRef.get()); 16 obj = null; 17 System.gc(); // 无论空间是否充足都应该回收弱引用对象 18 } 19 }
我们会发现弱引用的对象,只要GC调用则就会被回收
Java强、软、弱引用总结: