java WeakReference解决内存泄漏

来源:互联网 发布:笔记本分区软件 编辑:程序博客网 时间:2024/05/16 19:29
 java语言中为对象的引用分为了四个级别,分别为 强引用 、软引用、弱引用、虚引用。

本文只针对java中的弱引用进行一些分析,如有出入还请多指正。

在分析弱引用之前,先阐述一个概念:什么是对象可到达和对象不可到达状态。

其实很简单,我举个例子:

现在有如下两个类class A class B,在JVM上生成他们两个类的实例分别为 instance a  instance b

有如下表达式:

A a = new A();

B b = new B();

两个强引用对象就生成了,好吧,那么这个时候我做一下修改:

A a = new A();

B b = new B(a);

B的默认构造函数上是需要一个A的实例作为参数的,那么这个时候 A和B就产生了依赖,也可以说a和b产生了依赖,我们再用一个接近内存结构的图来表达:

 

a是对象A的引用,b是对象B的引用,对象B同时还依赖对象A,那么这个时候我们认为从对象B是可以到达对象A的。

于是我又修改了一下代码

A a = new A();

B b = new B(a);

a = null;

A对象的引用a置空了,a不再指向对象A的地址,我们都知道当一个对象不再被其他对象引用的时候,是会被GC回收的,很显然及时a=null,那么A对象也是不可能被回收的,因为B依然依赖与A,在这个时候,造成了内存泄漏!

那么如何避免上面的例子中内存泄漏呢?

很简单:

A a = new A();

B b = new B(a);

a = null;

b = null;

这个时候B对象再也没有被任何引用,A对象只被B对象引用,尽管这样,GC也是可以同时回收他们俩的,因为他们处于不可到达区域。

 

弱引用来了!

A a = new A();

WeakReference wr = new WeakReference(a);

//B b = new B(a);

 

当 a=null ,这个时候A只被弱引用依赖,那么GC会立刻回收A这个对象,这就是弱引用的好处!他可以在你对对象结构和拓扑不是很清晰的情况下,帮助你合理的释放对象,造成不必要的内存泄漏!!

 AbstractRefreshableApplicationContext.java   closeBeanFactory注意在置空键和值之后,spring还调用了serializableFactories .clear().来优化内存

  1. @Override  
  2.     protected final void closeBeanFactory() {  
  3.         synchronized (this.beanFactoryMonitor) {  
  4.             this.beanFactory.setSerializationId(null);  
  5.             this.beanFactory = null;  
  6.         }  
  7.     }  


  1. /** Map from serialized id to factory instance */  
  2.     private static final Map<String, Reference<DefaultListableBeanFactory>> serializableFactories =  
  3.             new ConcurrentHashMap<String, Reference<DefaultListableBeanFactory>>(8);  
  4.   
  5. /** 
  6.      * Specify an id for serialization purposes, allowing this BeanFactory to be 
  7.      * deserialized from this id back into the BeanFactory object, if needed. 
  8.      */  
  9.     public void setSerializationId(String serializationId) {  
  10.         if (serializationId != null) {  
  11.             serializableFactories.put(serializationId, new WeakReference<DefaultListableBeanFactory>(this));  
  12.         }  
  13.         else if (this.serializationId != null) {  
  14.             serializableFactories.remove(this.serializationId);  
  15.         }  
  16.         this.serializationId = serializationId;  
  17.     } 

自己演示

  1. import java.lang.ref.WeakReference;  
  2. import java.util.ArrayList;  
  3. import java.util.HashMap;  
  4. import java.util.List;  
  5. import java.util.Map;  
  6.   
  7. public class TestDemo {  
  8. public static void main(String[] args) {  
  9.     Map<Object, Object> map = new HashMap<>();    
  10.     Student a = new Student();  
  11.     Student b = new Student();  
  12.     Student c = new Student();  
  13.     Student d= new Student();  
  14.     WeakReference wr1 = new WeakReference(a);  
  15.     WeakReference wr2 = new WeakReference(b);  
  16.     WeakReference wr3 = new WeakReference(c);  
  17.     WeakReference wr4 = new WeakReference(d);  
  18.     map.put(wr1, wr3);    
  19.     map.put(wr2, wr4);   
  20.     b=null;  
  21.     System.gc();  
  22.     WeakReference temp1= (WeakReference) map.get(wr2);  
  23.     Student dd=(Student) temp1.get();  
  24.     dd.run("222");  
  25.     c=null;  
  26.     System.gc();  
  27.     WeakReference temp= (WeakReference) map.get(wr1);  
  28.     Student aa=(Student) temp.get();  
  29.     aa.run("1111");  
  30.       
  31.       
  32.       
  33. }  
  34. }  
  35. class Student{  
  36.     public void  run(String str) {  
  37.         System.out.println("its run "+str);  
  38.     }  
  39.       
  40. }  
  41.   
  42. its run 222  
  43. Exception in thread "main" java.lang.NullPointerException  
  44.     at test.TestDemo.main(TestDemo.java:31)  

总结:发现当将将map的键设为弱引用时置空,不会出现空指针异常,说明没有被垃圾回收,当将map的value设为弱引用置空,垃圾回收后会出现空指针异常,说明没有存在内存泄漏。即当弱引用被强引用的时候不会被垃圾回收。

  1. public static void main(String[] args) {  
  2.     Map<Object, Object> map = new HashMap<>();    
  3.     Student a = new Student();  
  4.     Student b = new Student();  
  5.     Student c = new Student();  
  6.     Student d= new Student();  
  7.     map.put(a, c);  
  8.     map.put(b, d);  
  9.       
  10.     a=null;  
  11.     System.gc();  
  12.     for (Entry<Object, Object> str :  map.entrySet()) {  
  13.         Student student=(Student) str.getValue();  
  14.         student.run("11");  
  15.     }  
  16.      
  17.     d=null;  
  18.     System.gc();  
  19.     Student object1 = (Student) map.get(b);  
  20.     object1.run("222");  
  21.     Student object = (Student) map.get(a);  
  22.    object.run("111");  
  23.      
  24. }  
  25. its run 11  
  26. its run 11  
  27. its run 222  
  28. Exception in thread "main" java.lang.NullPointerException  
  29.     at test.TestDemo.main(TestDemo.java:32)  

通过上述方法,发现当map键为普通引用的时候,当把键置空,则发现无法通过键获取value,但是实际上该值还存在,出现了内存泄漏,当将map的value设为普通引用,发现在在value置空后,并没有进行垃圾回收,出现了内存泄漏

原创粉丝点击