要想更好的理解SoftReferrence和WeakReference的机制,首先要说下Java中的对象和对象引用的概念。
对象,就是类的实例;对象引用,可以理解为操作对象的标识符,类似于c语音中的指针。
举个例子
Map map = new HashMap();
map即是对象引用;真正的对象是通过new创建的。
下面结合这个图说下对象和对象引用的相关问题
Obj1和Obj2就是通过new创建的内存,在Java中使用的是堆内存。
o1和o2就是对象引用,在Java中方法内的对象引用使用的是栈内存。在方法执行完成,就会释放。
Java中的GC主要针对的就是Obj1和Obj2这种堆内存。GC原理简单描述就是,当一个内存对象失去了所有的引用之后,GC 就可以将其回收。反过来说,如果这个对象还存在引用,那么它将不会被 GC 回收,哪怕是 Java 虚拟机抛出 OutOfMemoryError 。
Java中的内存泄漏,主要指,在内存对象明明已经不需要的时候,还仍然保留着这块内存和它的访问方式(引用)。
再举个极端的例子
Vector v = new Vector(10);
for (int i = 1; i < 100; i++){
Object o = new Object();
v.add(o);
o = null ;
}
在这个例子中,代码栈中存在Vector 对象的引用 v 和 Object 对象的引用 o 。在 For 循环中,我们不断的生成新的对象,然后将其添加到 Vector 对象中,之后将 o 引用置空。问题是当 o 引用被置空后,如果发生 GC ,我们创建的 Object 对象是否能够被 GC 回收呢?答案是否定的。因为, GC 在跟踪代码栈中的引用时,会发现 v 引用,而继续往下跟踪,就会发现 v 引用指向的内存空间中又存在指向 Object 对象的引用。也就是说尽管 o 引用已经被置空,但是 Object 对象仍然存在其他的引用,是可以被访问到的,所以 GC 无法将其释放掉。如果在此循环之后, Object 对象对程序已经没有任何作用,那么我们就认为此 Java 程序发生了内存泄漏。
还有比如Android中的Activity内存泄漏,下面的情况,当Activity关闭后,也不会释放Activity占用的内存,因为静态变量activity还在引用Activity。
static Activity activity;
public void setActivity(Activity a) {
this.activity = a;
}
下面介绍下Java中的引用类型
- 强引用(默认存在)
Object obj = new Object();
如果不将对象引用置null,那么GC是绝对不会回收内存,即使发生OOM。
Object obj = new Object();
...
obj = null;//这时候为垃圾回收器回收这个对象,至于什么时候回收,取决于垃圾回收器的算法
- 软引用(SoftReference) 在内存空间足够的情况下,除非内存空间接近临界值、jvm即将抛出oom的时候,垃圾回收器才会将该引用对象进行回收,避免了系统内存溢出的情况。
String sf = new String(“SoftReference”);
SoftReference sfRefer = new SoftReference(sf);
sf = null;
- 弱引用(WeakReference) 当垃圾回收器扫描到弱引用的对象的时候,不管内存空间是否足够,都会直接被垃圾回收器回收。不过也不用特别担心,垃圾回收器是一个优先级比较低的线程,因此不一定很快可以发现弱引用的对象。
String wf = new String(“WeakReference”);
WeakReference sfRefer = new WeakReference(wf);
wf = null;
下面通过例子说明下,SoftReference释放时机。
public class JavaTest {
public static void main(String[] args) {
byte[] strong1 = new byte[100000000];//用来占用大量内存
byte[] soft = new byte[900000000];
SoftReference softReference = new SoftReference(soft);
soft = null;
// byte[] strong2 = new byte[900000000];
System.out.println("SoftReference : " + softReference.get());
}
}
// 下面是输出结果
// SoftReference : [B@1b6d3586
// 该例子中,注释掉strong2的内存申请,则内存空间没有达到上限,因此没有释放soft引用指向的内存。
public class JavaTest {
public static void main(String[] args) {
byte[] strong1 = new byte[100000000];//用来占用大量内存
byte[] soft = new byte[900000000];
SoftReference softReference = new SoftReference(soft);
soft = null;
byte[] strong2 = new byte[900000000];//用来再次申请大量内存,是当前内存不够用
System.out.println("SoftReference : " + softReference.get());
}
}
// 下面是输出结果
// SoftReference : null
// 该例子中,打开strong2的内存申请,则内存空间达到上限,因此释放soft引用指向的内存。
public class JavaTest {
public static void main(String[] args) {
byte[] strong1 = new byte[100000000];//用来占用大量内存
byte[] soft = new byte[900000000];
SoftReference softReference = new SoftReference(soft);
// soft = null;//该行代码,将强引用置null,只保留软引用,才能保证内存不够时释放该内存,否则发生OOM
byte[] strong2 = new byte[900000000];//用来再次申请大量内存,是当前内存不够用
System.out.println("SoftReference : " + softReference.get());
}
}
// 下面是输出结果
// Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
// Java代码创建SoftReference后,必须将soft原对象设置null
下面看下WeakReference的释放时机
public class JavaTest {
public static void main(String[] args) {
byte[] strong1 = new byte[100000000];//用来占用大量内存
byte[] weak = new byte[900000000];
WeakReference weakReference = new WeakReference<>(weak);
weak = null;//该行代码,将强引用置null,只保留弱引用,才能保证释放该内存,否则发生OOM
// System.gc();//用来强制进行gc
// byte[] strong2 = new byte[900000000];
System.out.println("WeakReference : " + weakReference.get());
}
}
// 下面是输出结果
// WeakReference : [B@1b6d3586
// 在正常不执行gc情况,WeakReference引用指向的内存不会被释放
public class JavaTest {
public static void main(String[] args) {
byte[] strong1 = new byte[100000000];//用来占用大量内存
byte[] weak = new byte[900000000];
WeakReference weakReference = new WeakReference<>(weak);
weak = null;//该行代码,将强引用置null,只保留弱引用,才能保证释放该内存,否则发生OOM
System.gc();//用来强制进行gc
// byte[] strong2 = new byte[900000000];
System.out.println("WeakReference : " + weakReference.get());
}
}
// 下面是输出结果
// WeakReference : null
// 执行gc情况,即使内存没达到上限,WeakReference引用指向的内存会被释放
public class JavaTest {
public static void main(String[] args) {
byte[] strong1 = new byte[100000000];//用来占用大量内存
byte[] weak = new byte[900000000];
WeakReference weakReference = new WeakReference<>(weak);
weak = null;//该行代码,将强引用置null,只保留弱引用,才能保证释放该内存,否则发生OOM
// System.gc();//用来强制进行gc
byte[] strong2 = new byte[900000000];
System.out.println("WeakReference : " + weakReference.get());
}
}
// 下面是输出结果
// WeakReference : null
// 可以看出,申请内存达到上限时,有可能执行gc,WeakReference引用指向的内存会被释放
下面再来看下全局引用对象的情况
public class JavaTest {
private static Map<String, WeakReference> weakMap = new HashMap<>();
public static void main(String[] args) {
byte[] strong1 = new byte[100000000];
byte[] weak = new byte[900000000];
WeakReference weakReference = new WeakReference<>(weak);
// weak = null;
weakMap.put("weak", weakReference);
// System.gc();
byte[] strong2 = new byte[900000000];
System.out.println("WeakReference : " + weakMap.get("weak").get());
}
}
// 下面是输出结果
// Exception in thread "main" java.lang.OutOfMemoryError:
下面我们将创建WeakReference的方法放到另外的方法里再看看运行效果
public class JavaTest {
private static Map<String, WeakReference> weakMap = new HashMap<>();
public static void main(String[] args) {
byte[] strong1 = new byte[100000000];
newWeak();
// System.gc();
byte[] strong2 = new byte[900000000];
System.out.println("WeakReference : " + weakMap.get("weak").get());
}
private static void newWeak() {
byte[] weak = new byte[900000000];
WeakReference weakReference = new WeakReference<>(weak);
// weak = null;
weakMap.put("weak", weakReference);
}
}
// 下面是输出结果
// WeakReference : null
// 可以看到在newWeak中,没有将变量weak设置成null,在内存不够时,也会释放WeakReference中的内存
// 所以可以看出,在newWeak方法结束后,weak这个引用,自动设置成了null
今天的文章SoftReferenec和WeakReference理解分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/18163.html