Mono内存简介
Mono内存是Unity引擎通过Mono虚拟机管理的所有C#对象(即MonoObject相关)的内存占用。在使用IL2CPP模式时,Unity实际上使用的是重写的IL2CPP虚拟机,此时Mono内存对应于IL2CPP虚拟机管理的所有C#翻译后的对象(即Il2cppObject相关)。尽管如此,由于历史原因,Unity Profiler中仍然使用“Mono内存”这一术语。值得注意的是,Unity在新版本中已经意识到这一不准确的称呼,并在2020.3.16f1版本中将其修改为GC(垃圾回收)。
Unity Profiler中的内存统计
在Unity Profiler中,内存统计通常包括两个值:Used Total和Reserved Total。很多开发者发现这两个值与通过其他工具(如PSS或XCode Memory)获取的内存占用数据不一致,这种情况是正常的,原因如下:
内存管理范围:
- Unity工具统计的内存仅包括通过引擎自身内存管理器分配的内存,而Android或iOS统计的内存还包括应用进程运行所需的其他内存,例如JVM相关内存(Android特有)、线程栈内存、GPU渲染相关内存以及其他SDK分配的内存等。这些内存不在Unity引擎的管理范围内,因此无法统计在内。
操作系统的内存统计算法:
- 不同操作系统的内存统计算法不同。例如,iOS 12版本修改了Metal相关内存的统计方式,使其归属于应用,这导致相同应用在不同iOS版本中的内存占用差异显著。
内存分配与系统统计的关系:
- 应用内存的占用与通过内存分配函数分配的内存大小并不总是一一对应。例如,直接通过
malloc
分配的内存可能不会立即反映在PSS数值上。在iOS中,内存管理器将内存状态分为Clean和Dirty,只有在写入数据后,Dirty状态的内存才会被统计到PSS中。Android系统也有类似的内存管理机制。
- 应用内存的占用与通过内存分配函数分配的内存大小并不总是一一对应。例如,直接通过
Unity Profiler中的Used Total和Reserved Total
Unity引擎底层通过多种内存分配器(如HeapAllocator、BucketAllocator、DynamicHeapAllocator等)来管理内存分配和释放。因此,Used Total和Reserved Total实际上是内存管理器统计的所有内存分配器分配和使用的内存总大小。
- Used Total:当前已使用的内存总量。
- Reserved Total:当前已申请的内存总量。
Unity引擎为了提高性能,很多内存分配器采用了内存池的概念。这意味着应用在请求内存时,并不是每次都直接向操作系统申请,而是预先向操作系统申请一块大的内存区域,然后由内存管理器进行管理。这样可以减少系统调用的次数,提高内存分配和回收的效率。
Mono内存的获取工具
除了Unity Profiler,还有其他工具可以获取Mono内存占用:
iOS系统:可以通过XCode的Instruments Allocations工具获取Mono内存占用。在工具中切换到All Heap,Mono内存对应的Memory Tag为255。
Android系统:目前没有直接的工具来查看具体的Mono内存占用,开发者可以使用
adb dumpsys meminfo
命令来获取内存信息,其中Mono内存主要体现在Unknown或Native部分(具体表现可能因机型而异)。
总结
了解Mono内存的管理和统计方式对于优化Unity应用的性能至关重要。通过合理使用Unity Profiler和其他工具,开发者可以更好地监控和管理内存使用,确保应用在不同平台上的流畅运行。
二、何谓GC Alloc