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置空后,并没有进行垃圾回收,出现了内存泄漏
本文只针对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置空后,并没有进行垃圾回收,出现了内存泄漏
相关文章推荐
- mono中的内存泄漏和WeakReference(弱引用)的使用
- 升级XCode7.3 后RAC报错“Cannot create __weak reference in file using manual reference counting”解决办法
- java 使用AtomicStampedReference解决ABA问题需要注意的坑
- 解决jdk8之The type java.util.Map$Entry cannot be resolved. It is indirectly referenced from required .
- Java引用总结--StrongReference、SoftReference、WeakReference、PhantomReference
- Java中的WeakReference讲解
- Java引用总结--StrongReference、SoftReference、WeakReference、PhantomReference
- Android 开发系列(3) - native代码调用java代码出现attempt using stale local reference错误及解决办法
- 解决 Cannot synthesize weak property in file using manual reference counting
- Java WeakReference的理解与使用
- Java中的WeakReference解析
- 什么是Java的弱引用(Weak Reference)
- java弱引用(WeakReference)和SoftReference的区别以及在android内存处理的作用
- Java WeakReference的理解与使用
- iOS---解决Cannot synthesize weak property in file using manual reference counting
- Java中WeakReference、WeakHashMap、SoftReference、ReferenceQueue的作用和使用场景
- Java WeakReference的理解与使用
- java内存泄露分析,java弱引用(weakreference)
- 不只是给面试加分 -- Java WeakReference的理解与使用
- java 中 Cannot make a static reference to the non-static 解决方法