有没有办法在Unity中准确测量堆分配以进行单元测试?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了有没有办法在Unity中准确测量堆分配以进行单元测试?相关的知识,希望对你有一定的参考价值。

在Unity中每一帧在堆上分配临时对象都是昂贵的,我们都尽力通过缓存堆对象和避免垃圾生成功能来避免这种情况。虽然有些东西会产生垃圾,但这并不总是很明显。例如:

enum MyEnum {
  Zero,
  One,
  Two
}

List<MyEnum> MyList = new List<MyEnum>();
MyList.Contains(MyEnum.Zero); // Generates garbage

MyList.Contains()生成垃圾,因为List的默认相等比较器使用objects,这导致枚举值类型的装箱。

为了防止像这样的无意堆分配,我希望能够在我的单元测试中检测它们。

我认为这有两个要求:

  1. 一个函数返回堆分配的内存量
  2. 一种防止在测试期间发生垃圾收集的方法

我还没有找到一个干净的方法来确保#2。我发现#1最接近的是GC.GetTotalMemory()

        [UnityTest]
        IEnumerator MyTest()
        {
          long before = GC.GetTotalMemory(false);
          const int numObjects = 1;
          for (int i = 0 ; i < numObjects; ++i)
          {
            System.Version v = new System.Version();
          }
          long after = GC.GetTotalMemory(false);
          Assert.That(before == after); 
        }

问题是GC.GetTotalMemory()在此测试之前和之后返回相同的值。我怀疑Unity / Mono只分配来自系统堆的内存,比如4kb,所以你需要在Unity / Mono实际上从系统堆请求更多内存之前分配<= 4kb,此时GC.GetTotalMemory()将返回不同的值。我确认如果我将numObjects更改为1000,GC.GetTotalMemory()会返回之前和之后的不同值。

总而言之,1。如何准确地获取堆分配内存的数量,精确到字节和2.垃圾收集器可以在我的测试体内运行,如果是这样,是否有任何非hacky方式禁用GC在我的测试期间

TL; DR感谢您的帮助!

答案

我在Unity答案上发布了同样的问题并得到了答复:

https://answers.unity.com/questions/1535588/is-there-a-way-to-accurately-measure-heap-allocati.html

不,基本上不可能。您可以在循环中多次运行单元测试,并希望它生成足够的垃圾以导致GC.GetTotalMemory()返回的值发生更改,但这就是它。

以上是关于有没有办法在Unity中准确测量堆分配以进行单元测试?的主要内容,如果未能解决你的问题,请参考以下文章

在MSA中MSA是啥意思

Unity WebGL开发中的内存分配问题(分析Unity堆数据)

堆、栈和数据存储单元的大小

查找内存应用程序正在仪器中使用?

如何准确测量流经命名管道的比特率?

有没有办法在 .NET 运行时预分配堆,比如 Java 中的 -Xmx/-Xms?