Java之 对象引用
内存管理
Java的内存管理就是内存空间的分配和释放的过程。
示例一
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
for (int i = 0; i < 10000000; i++) {
MyMemory myMemory = new MyMemory(this);
myMemory.addCotent("添加内容 + " + i);
}
}
public String addString(String text) {
return "从外面的Main 添加数据 ==" + text;
}
public static class MyMemory {
String text = "";
MainActivity main;
MyMemory(MainActivity main) {
text = text + "1111";
this.main = main;
}
public void addCotent(String add) {
text = text + add;
main.addString(text);
}
}
}
示例二
public class MemoryLeakTest {
public static void main(String[] args) {
Vector v = new Vector(100000000);
for(int i=0;i<v.size();i++){
Object o = new Object();
v.add(o);
o = null;
}
}
说明
在for循环中,循环申请Object对象,每申请一个放入Vector中,然后把Object对象置空。此时,对于Object对象来说,与GC Roots是有通路的,因为由Vector对象引用,但在Object对象置空后,Object对象又没有用途了,所以对于所有的Object对象来说,与GC Roots有通路,但是又没有用,所以造成了堆内存泄露。
什么是GC Roots?
什么是通路
ThreadLocal中,获取到线程私有对象是通过线程持有的一个threadLocalMap,然后传入ThreadLocal当做key获取到对象的,这时候就有个问题,如果你在使用完ThreadLocal之后,将其置为null,这时候这个对象并不能被回收,因为他还有 ThreadLocalMap->entry->key的引用,直到该线程被销毁,但是这个线程很可能会被放到线程池中不会被销毁,这就产生了内存泄露。
jdk是通过弱引用来解决的这个问题的,entry中对key的引用是弱引用,当你取消了ThreadLocal的强引用之后,他就只剩下一个弱引用了,所以也会被回收。
引用与回收
引用
不同的引用类型,主要体现的是对象不同的可达性(reachable)状态和对垃圾收集的影响。
- 强引用
只要还有强一弄指向一个对象,就能表能对象还“活着”,垃圾收集器不会碰这种对象。
Object o = new Object();
- 软引用
相对强引用弱化一些的引用,可以让对象豁免一些垃圾收集,只有JVM认为内存不足时,才会试图回收软引用对象。
Object o = new Object();
SoftReference sr = new SoftReference(prev);
if(sr.get() != null) {
o1 = (Object)sr.get();
} else {
o = new Object();
sr = new SoftReference(o1);
}
- 弱引用
不能是对象豁免垃圾回收,只要被扫描到就会被回收
Object o = new Object();
WeakReference sr = new WeakReference(prev);
if(sr.get() != null) {
o1 = (Object)sr.get();
} else {
o = new Object();
sr = new WeakReference(o);
}
- 幻象引用(虚引用)
一个对象是都有虚引用的存在都不会对生存时间都构成影响,也无法通过虚引用来获取对一个对象的真实引用。唯一的用处:能在对象被GC时收到系统通知
弱引用是说JVM认为内存不足是什么时候,如果不回收会发生什么问题?
可达性
reachable.png判断对象可达性,是 JVM 垃圾收集器决定如何处理对象的一部考虑。
- 强可达
一个对象可以被一些线程直接使用而不用通过其他引用对象,那么它就是强可达 - 软可达
一个对象没有强可达性,但是它可以通过一个软引用(soft reference.)来使用,那么它就具有软可达性。 - 弱可达
一个对象既没有强可达性,也没有软可达性,但是它可以通过一个弱引用(weak reference)来使用,那么他就具有弱可达性 - 虚可达
一个对象既没有强可达性,也没有软可达性、弱可达性,他已经被finalized,并且有一些虚引用(phantom reference)指向它,那么它就具有虚可达性。 - 不可达
所有引用类型,都是抽象类 java.lang.ref.Reference 的子类。可以查看reference 的源码
public abstract class Reference<T> {
private T referent;
volatile ReferenceQueue<? super T> queue;
Reference next;
private transient Reference<T> discovered;
private static Reference.Lock lock = new Reference.Lock(null);
private static Reference<Object> pending = null;
// .............
// .............
public T get() {
return this.referent;
}
public void clear() {
this.referent = null;
}
}
参考
Java中的强引用,软引用,弱引用,虚引用有什么用?
java内存模型和内存分配
浅析java内存管理机制
第4讲 | 强引用、软引用、弱引用、幻象引用有什么区别
ava四种引用---强、软、弱、虚的知识点总结