您的位置:首页 > Web前端

java WeakReference解决内存泄漏

2017-12-01 00:18 387 查看
 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().来优化内存

@Override  

    protected final void closeBeanFactory() {  

        synchronized (this.beanFactoryMonitor) {  

            this.beanFactory.setSerializationId(null);  

            this.beanFactory = null;  

        }  

    }  

/** Map from serialized id to factory instance */  

    private static final Map<String, Reference<DefaultListableBeanFactory>> serializableFactories =  

            new ConcurrentHashMap<String, Reference<DefaultListableBeanFactory>>(8);  

  

/** 

     * Specify an id for serialization purposes, allowing this BeanFactory to be 

     * deserialized from this id back into the BeanFactory object, if needed. 

     */  

    public void setSerializationId(String serializationId) {  

        if (serializationId != null) {  

            serializableFactories.put(serializationId, new WeakReference<DefaultListableBeanFactory>(this));  

        }  

        else if (this.serializationId != null) {  

            serializableFactories.remove(this.serializationId);  

        }  

        this.serializationId = serializationId;  

    } 

自己演示

import java.lang.ref.WeakReference;  

import java.util.ArrayList;  

import java.util.HashMap;  

import java.util.List;  

import java.util.Map;  

  

public class TestDemo {  

public static void main(String[] args) {  

    Map<Object, Object> map = new HashMap<>();    

    Student a = new Student();  

    Student b = new Student();  

    Student c = new Student();  

    Student d= new Student();  

    WeakReference wr1 = new WeakReference(a);  

    WeakReference wr2 = new WeakReference(b);  

    WeakReference wr3 = new WeakReference(c);  

    WeakReference wr4 = new WeakReference(d);  

    map.put(wr1, wr3);    

    map.put(wr2, wr4);   

    b=null;  

    System.gc();  

    WeakReference temp1= (WeakReference) map.get(wr2);  

    Student dd=(Student) temp1.get();  

    dd.run("222");  

    c=null;  

    System.gc();  

    WeakReference temp= (WeakReference) map.get(wr1);  

    Student aa=(Student) temp.get();  

    aa.run("1111");  

      

      

      

}  

}  

class Student{  

    public void  run(String str) {  

        System.out.println("its run "+str);  

    }  

      

}  

  

its run 222  

Exception in thread "main" java.lang.NullPointerException  

    at test.TestDemo.main(TestDemo.java:31)  

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

public static void main(String[] args) {  

    Map<Object, Object> map = new HashMap<>();    

    Student a = new Student();  

    Student b = new Student();  

    Student c = new Student();  

    Student d= new Student();  

    map.put(a, c);  

    map.put(b, d);  

      

    a=null;  

    System.gc();  

    for (Entry<Object, Object> str :  map.entrySet()) {  

        Student student=(Student) str.getValue();  

        student.run("11");  

    }  

     

    d=null;  

    System.gc();  

    Student object1 = (Student) map.get(b);  

    object1.run("222");  

    Student object = (Student) map.get(a);  

   object.run("111");  

     

}  

its run 11  

its run 11  

its run 222  

Exception in thread "main" java.lang.NullPointerException  

    at test.TestDemo.main(TestDemo.java:32)  

通过上述方法,发现当map键为普通引用的时候,当把键置空,则发现无法通过键获取value,但是实际上该值还存在,出现了内存泄漏,当将map的value设为普通引用,发现在在value置空后,并没有进行垃圾回收,出现了内存泄漏
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: