参考:
总结:
Unity游戏运行时内存占用分以下几部分:
- Mono堆:C# 代码
- Native堆:资源,unity引擎逻辑,第三方逻辑。
- 库代码:Unity库,第三方库。
Mono堆:
代码分配的内存,是通过Mono虚拟机,分配在Mono堆内存上的,其内存占用量一般较小,主要目的是程序猿在处理程序逻辑时使用;
通过System命名空间中的接口分配的内存,将会通过Mono Runtime分配在Mono堆。
Mono内存分为两部分,
- 已用内存(used):已用内存指的是mono实际需要使用的内存
- 堆内存(heap):堆内存指的是mono向操作系统申请的内存
- 两者的差值就是mono的空闲内存。
Mono中的GC主要有以下几个步骤:
- 停止所有需要mono内存分配的线程。
- 遍历所有已用内存,找到那些不再需要使用的内存,并进行标记。
- 释放被标记的内存到空闲内存。
- 重新开始被停止的线程。
- GC释放的内存只会留给mono使用,并不会交还给操作系统,因此mono堆内存是只增不减的。
Mono内存泄漏分析
典型泄漏:
代码侧的泄漏,由于“存在该释放却没有释放的错误引用”,导致回收机制认为目标对象不是“垃圾”,以至于不能被回收
手动内存管理的泄漏,资源卸载是主动触发的,在触发了资源卸载之后,才清除对资源引用,但是有人忘记主动卸载。
但是,现在需要扩大定义:把对象已经不再需要使用却没有被GC回收的情况称为mono内存泄漏
面临的问题
- 托管堆在GC后内存仍不足时,会继续申请新的内存,但GC所释放的内存会留给Mono使用并不会还给操作系统,这会导致游戏内存占用越来越高。
- GC时会暂停那些需要Mono内存分配的线程,无论是否在主线程调用都会造成一定程度的卡顿。
- GC过程会进行遍历标记的耗时操作,虽然优化了内存,但无疑大大加重了CPU的负担。