美文网首页
Java之 对象引用

Java之 对象引用

作者: 五月笙 | 来源:发表于2021-08-30 11:31 被阅读0次

    内存管理

    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四种引用---强、软、弱、虚的知识点总结

    相关文章

      网友评论

          本文标题:Java之 对象引用

          本文链接:https://www.haomeiwen.com/subject/krumnktx.html