【Unity2018.2.19f 编辑器下测试】【Heap Exploer 工具】【unity-memoryprofiler工具】
问题源于 UWA上的一个帖子: 同时也听同事说到类似的问题。 关于引用 无法GC的问题表示疑问?
测试如下:
空场景, 添加如下:
添加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操作。
Play 场景。 我搜索 “zhanshi” 可以看到包含的内容, 在预期里, 序列化资源和实例化对象。
现在要做的是在 Test 组件右键执行 "Destory 释放结果:"
然后再看剩余情况: 其中有Avatar 被C# 引用着。
VS 调试查看 Test 中的变量情况 :
重点就是 zhanshi 相关的GameObject 对象和 TestComponentRef 组件对象在内存中就是被清除的。 忘了截取GC执行次数
==================================================================================
注意上方的名字搜索不到了, 不代表内存被回收了, 还好工具记录着内存地址, 下图是我新的测试,截图的内存地址根之前的截图不同了。 (不管怎么调用GC, 下面的内存对象一直都在, 还有一个现象就是C# 对象要比C++ 对象的Size小很多???)
如果测试的话, 不算完整, 手动在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的API 我获取所有的 Object, C#层的GameObject 就是继承自 Object , 但是销毁之后也是得不到了的?
==================================================================================
在继续执行 Test 组件的 命令 "UnloadUnusedAssets 释放结果:" 答案就是 zhanshi 相关的都没有了!!! C#对象中也是搜索不到的, 除非工具有问题(我也是有怀疑的, 有时间我在使用Unity的Memory Profiler 再做一下测试)
完结。
在使用 unity-memoryprofiler 工具做上面三个操作的结果也是一样的, 如下图。
谢谢~~ 通过测试的结果发现, 原来的名字肯定不存在了, 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 ++对象。