做一个关于Unity (GameObject/Component引用无法 GC的测试

 

【Unity2018.2.19f   编辑器下测试】【Heap Exploer 工具】【unity-memoryprofiler工具】

 

问题源于 UWA上的一个帖子:    同时也听同事说到类似的问题。   关于引用 无法GC的问题表示疑问?

做一个关于Unity (GameObject/Component引用无法 GC的测试_第1张图片

 

 

测试如下:

空场景,  添加如下:

做一个关于Unity (GameObject/Component引用无法 GC的测试_第2张图片

 做一个关于Unity (GameObject/Component引用无法 GC的测试_第3张图片

        添加Test 脚本:

using System;
using UnityEngine;

public class Test : MonoBehaviour
{

    public sealed class GCWatcher
    {
        private int m_startCount;
        public int Count { get; private set; }
        ///开始测量
        public void Start()
        {
            m_startCount = GC.CollectionCount(0);
            Count = 0;
        }
        //测量
        public void Stop()
        {
            Count = GC.CollectionCount(0) - m_startCount;
        }
    }

    public GameObject obj;
    public TestComponentRef com;

    [ContextMenu("Destory 释放结果:")]
    public void TestGC()
    {
        Destroy(obj);
    }
    [ContextMenu("DestroyImmediate 释放结果:")]
    public void TestGC2()
    {
        DestroyImmediate(obj);
    }
    [ContextMenu("UnloadUnusedAssets 释放结果:")]
    public void TestGC3()
    {
        Resources.UnloadUnusedAssets();
    }

    private GCWatcher watcher;
    private void Awake()
    {
        watcher = new GCWatcher();
        watcher.Start();
    }

    private void OnGUI()
    {
        watcher.Stop();
        GUILayout.Label(watcher.Count.ToString());
    }
}

           代码中有统计GC次数的逻辑, 我要确定 确实执行了GC操作。 

做一个关于Unity (GameObject/Component引用无法 GC的测试_第4张图片

      Play 场景。       我搜索  “zhanshi”    可以看到包含的内容,   在预期里,  序列化资源和实例化对象。 

做一个关于Unity (GameObject/Component引用无法 GC的测试_第5张图片

             现在要做的是在   Test   组件右键执行    "Destory 释放结果:"

然后再看剩余情况:    其中有Avatar 被C# 引用着。  

做一个关于Unity (GameObject/Component引用无法 GC的测试_第6张图片

做一个关于Unity (GameObject/Component引用无法 GC的测试_第7张图片

VS 调试查看 Test 中的变量情况 :

做一个关于Unity (GameObject/Component引用无法 GC的测试_第8张图片

做一个关于Unity (GameObject/Component引用无法 GC的测试_第9张图片

             重点就是  zhanshi 相关的GameObject 对象和 TestComponentRef 组件对象在内存中就是被清除的。  忘了截取GC执行次数

==================================================================================

         注意上方的名字搜索不到了, 不代表内存被回收了, 还好工具记录着内存地址, 下图是我新的测试,截图的内存地址根之前的截图不同了。    (不管怎么调用GC,  下面的内存对象一直都在,            还有一个现象就是C# 对象要比C++ 对象的Size小很多???)

            我试验过,同样的方式查看 C++内存地址,是搜索不到的 ~ 做一个关于Unity (GameObject/Component引用无法 GC的测试_第10张图片做一个关于Unity (GameObject/Component引用无法 GC的测试_第11张图片

做一个关于Unity (GameObject/Component引用无法 GC的测试_第12张图片

 

        如果测试的话, 不算完整,  手动在Hierachy 面板上销毁  Directional Light  对象,  隔几秒之后在  通过内存地址看C#对象会发现此时 对象没有了 ~~~

 

               这里还有做过其他尝试,通过分析内存比如 Mono 内存, Unity堆内存。   

        public void Snapshot()
        {
            Used = (Profiler.GetMonoUsedSizeLong() >> 10) / 1024f;

            // 较大的堆需要更多的GC时间,但运行频率较低
            Total = (Profiler.GetMonoHeapSizeLong() >> 10) / 1024f;
            UsedText = Used.ToString("0.0") + " MB";
            TotalText = Total.ToString("0.0") + " MB";
        }

        Debug.LogError(string.Format("Use: {0}", m_monoMemoryChecker.UsedText));
        Debug.LogError(string.Format("Total: {0}", m_monoMemoryChecker.TotalText));            统计肯定没有问题, 但是影响的因素太多了,    string 的临时对象, 如果有OnGUI 函数的话 每次也有堆分配。 这种方式行不通。  不过我把,  测试的脚本变的内存占用比较大, 这样有它没它的量级就不一样了, 可以看出大概。

做一个关于Unity (GameObject/Component引用无法 GC的测试_第13张图片

 

还有一点  Unity的API   我获取所有的 Object,    C#层的GameObject 就是继承自 Object , 但是销毁之后也是得不到了的?

做一个关于Unity (GameObject/Component引用无法 GC的测试_第14张图片

做一个关于Unity (GameObject/Component引用无法 GC的测试_第15张图片

==================================================================================

           在继续执行 Test 组件的 命令  "UnloadUnusedAssets 释放结果:"               答案就是  zhanshi 相关的都没有了!!!  C#对象中也是搜索不到的, 除非工具有问题(我也是有怀疑的, 有时间我在使用Unity的Memory Profiler 再做一下测试)

做一个关于Unity (GameObject/Component引用无法 GC的测试_第16张图片

 

完结。 

 

 

在使用  unity-memoryprofiler 工具做上面三个操作的结果也是一样的, 如下图。  

做一个关于Unity (GameObject/Component引用无法 GC的测试_第17张图片

做一个关于Unity (GameObject/Component引用无法 GC的测试_第18张图片

做一个关于Unity (GameObject/Component引用无法 GC的测试_第19张图片

  谢谢~~               通过测试的结果发现,  原来的名字肯定不存在了,    C++ 对象也不存在了,  C#对象存在, 但是引用的C++对象指针是null了 。    

          当你获得类型为“GameObject”的C#对象时,它几乎不包含任何东西。这是因为Unity是一个C / C ++引擎。关于这个GameObject的所有实际信息(它的名称,它拥有的组件列表,它的HideFlags等)都存在于c ++中。c#对象唯一拥有的是指向本机对象的指针。我们将这些c#对象称为“包装器wrapper对象”。这些c ++对象(如GameObject)的生命周期以及从UnityEngine.Object派生的所有其他内容都是明确管理的。加载新场景时会Destory这些对象。或者当你调用Object.Destroy(myObject);        使用垃圾收集器以c#方式管理c#对象的生命周期。这意味着可以使用仍然存在的c#wrapper对象,它包装已经被销毁的c ++对象。

 

你可能感兴趣的:(学unity涨知识)