Unity中由引用导致的内存泄露由弱引用解决

转载自:http://blog.csdn.net/wpapa/article/details/51503444

我们大家有时候在做 unity 项目的时候,游戏后期最常见的问题,应该就是内存泄漏了。 
其实这里面有一些小细节,就可能在你不知不觉间导致内存泄漏的发生。 
这里说说释放对象时容易发生的问题。

先来看一段代码:

    private float m_countdown = 10;
    private bool m_turnOn = false;

    TestB m_tb;
    TestA m_ta;

    // Use this for initialization
    void Start()
    {
        m_turnOn = true;

        m_tb = new TestB();
        m_ta = new TestA(m_tb);
    }

    // Update is called once per frame
    void Update()
    {
        if (m_turnOn == false)
            return;

        if (m_countdown >= 0)
        {
            m_countdown -= Time.deltaTime;
        }
        else
        {
            m_turnOn = false;

            m_ta = null;

            GC.Collect();
            Debug.LogError("清理内存");
        }
    }

    public class TestA
    {
        private long[] m_array;

        TestB m_tb;

        public TestA(TestB tb)
        {
            m_array = new long[100000000];

            m_tb = tb;
            m_tb.TestFun();
        }
    }
    public class TestB
    {
        private long[] m_array;

        public TestB()
        {
            m_array = new long[100000000];
        }

        public void TestFun()
        {
            Debug.LogError("测试方法");
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64

代码内容十分的简单,我就不说了,我们来看用 Profiler 工具所截取的内存用量显示

gc前:

Unity中由引用导致的内存泄露由弱引用解决_第1张图片
我们看到了,Mono内存是 2.99G (别问我mono内存是什么。。。)

gc后:

Unity中由引用导致的内存泄露由弱引用解决_第2张图片
我们看到了,经过一次gc后,内存降到了 2.24G ,这时候,也许有人该说了,内存这不是降低了吗,没错呀╮(╯▽╰)╭。我要告诉你,少年,你高兴的太早了!

现在,我们再来看一段代码:

    private float m_countdown = 10;
    private bool m_turnOn = false;

    WeakReference m_wrf_b;
    TestA m_ta;

    // Use this for initialization
    void Start()
    {
        m_turnOn = true;

        TestB tb = new TestB();
        m_wrf_b = new WeakReference(tb);

        m_ta = new TestA(m_wrf_b);
    }

    // Update is called once per frame
    void Update()
    {
        if (m_turnOn == false)
            return;

        if (m_countdown >= 0)
        {
            m_countdown -= Time.deltaTime;
        }
        else
        {
            m_turnOn = false;

            m_ta = null;

            GC.Collect();
            Debug.LogError("清理内存");
        }
    }

    public class TestA
    {
        private long[] m_array;

        WeakReference m_wrf;

        public TestA(WeakReference wrf)
        {
            m_array = new long[100000000];

            m_wrf = wrf;

            TestB tb = (TestB)m_wrf.Target;
            tb.TestFun();
        }
    }
    public class TestB
    {
        private long[] m_array;

        public TestB()
        {
            m_array = new long[100000000];
        }

        public void TestFun()
        {
            Debug.LogError("测试方法");
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68

现在,让我们再来做一遍之前的过程。

gc前:

Unity中由引用导致的内存泄露由弱引用解决_第3张图片

gc后:

Unity中由引用导致的内存泄露由弱引用解决_第4张图片

所以这一切是为什么呢?

主要原因就是因为我们new出来的这个对象,其实在c#中被称作强引用对象。 
举例来说就是,在A对象依赖于B对象时,如果我们把B释放了,你会认为我们连A也一起释放了。 
其实这只是你的错觉,真实情况是你释放了B,但是A是强引用类型,结果你的A找不到依赖了,变成内存泄漏了。。。

解决这个问题有2种办法,一种就是: 
你在释放B的同时,把A也一起干掉,像第一段代码的gc那里改成这样:

m_tb = null;
m_ta = null;
  • 1
  • 2

或者用第2段代码里的方法: 
正所谓有强就有弱,WeakReference应该是c#从java那里学来的,叫做弱引用对象,原理我就不说了,你去查查就明白了。 
WeakReference就是专门用来解决因为这种依赖关系造成的gc释放问题。 
当然WeakReference也不是万能的,有时可能gc已经把对象释放了,但是你new出来的WeakReference是不会释放的,结果你还用它去取存放在里面的对象,那时你取到的可能就是个null了。这时候,你就需要再重新把对象创建出来。 
所以请结合你自己系统的底层架构,合理,正确的去使用弱引用对象。


你可能感兴趣的:(Unity3D基础)