unity 内存方面优化

大城市里の小女人 提交于 2020-03-17 12:29:58

作者写的很好,看了他的书收获很大。以下内容摘自:https://www.cnblogs.com/murongxiaopifu/p/4284988.html

既然要聊Unity3D运行时候的内存优化,那我们自然首先要知道Unity3D游戏引擎是如何分配内存的。大概可以分成三大部分:

  1. Unity3D内部的内存
  2. Mono的托管内存
  3. 若干我们自己引入的DLL或者第三方DLL所需要的内存。

第3类不是我们关注的重点,所以接下来我们会分别来看一下Unity3D内部内存Mono托管内存,最后还将分析一个官网上Assetbundle的案例来说明内存的管理。

Unity3D内部内存

Unity3D的内部内存都会存放一些什么呢?各位想一想,除了用代码来驱动逻辑,一个游戏还需要什么呢?对,各种资源。所以简单总结一下Unity3D内部内存存放的东西吧:

  • 资源:纹理、网格、音频等等
  • GameObject和各种组件。
  • 引擎内部逻辑需要的内存:渲染器,物理系统,粒子系统等等

Mono托管内存

因为我们的游戏脚本是用C#写的,同时还要跨平台,所以带着一个Mono的托管环境显然必须的。那么Mono的托管内存自然就不得不放到内存的优化范畴中进行考虑。那么我们所说的Mono托管内存中存放的东西和Unity3D内部内存中存放的东西究竟有何不同呢?其实Mono的内存分配就是很传统的运行时内存的分配了:

  • 值类型:int型啦,float型啦,结构体struct啦,bool啦之类的。它们都存放在堆栈上(注意额,不是堆所以不涉及GC)。
  • 引用类型:其实可以狭义的理解为各种类的实例。比如游戏脚本中对游戏引擎各种控件的封装。其实很好理解,C#中肯定要有对应的类去对应游戏引擎中的控件。那么这部分就是C#中的封装。由于是在堆上分配,所以会涉及到GC。

而Mono托管堆中的那些封装的对象,除了在在Mono托管堆上分配封装类实例化之后所需要的内存之外,还会牵扯到其背后对应的游戏引擎内部控件在Unity3D内部内存上的分配。

举一个例子:

一个在.cs脚本中声明的WWW类型的对象www,Mono会在Mono托管堆上为www分配它所需要的内存。同时,这个实例对象背后的所代表的引擎资源所需要的内存也需要被分配。

一个WWW实例背后的资源:

  • 压缩的文件
  • 解压缩所需的缓存
  • 解压缩之后的文件

如图:

那么下面就举一个AssetBundle的例子:

Assetbundle的内存处理

以下载Assetbundle为例子,聊一下内存的分配。匹夫从官网的手册上找到了一个使用Assetbundle的情景如下:

复制代码
IEnumerator DownloadAndCache (){
        // Wait for the Caching system to be ready
        while (!Caching.ready)
            yield return null;

        // Load the AssetBundle file from Cache if it exists with the same version or download and store it in the cache
        using(WWW www = WWW.LoadFromCacheOrDownload (BundleURL, version)){
            yield return www; //WWW是第1部分
            if (www.error != null)
                throw new Exception("WWW download had an error:" + www.error);
            AssetBundle bundle = www.assetBundle;//AssetBundle是第2部分
            if (AssetName == "")
                Instantiate(bundle.mainAsset);//实例化是第3部分
            else
                Instantiate(bundle.Load(AssetName));
                    // Unload the AssetBundles compressed contents to conserve memory
                    bundle.Unload(false);

        } // memory is freed from the web stream (www.Dispose() gets called implicitly)
    }
}
复制代码

内存分配的三个部分匹夫已经在代码中标识了出来:

  1. Web Stream:包括了压缩的文件,解压所需的缓存,以及解压后的文件。
  2. AssetBundle:Web Stream中的文件的映射,或者说引用。
  3. 实例化之后的对象就是引擎的各种资源文件了,会在内存中创建出来。

那就分别解析一下:

WWW www = WWW.LoadFromCacheOrDownload (BundleURL, version)
  1. 将压缩的文件读入内存中
  2. 创建解压所需的缓存
  3. 将文件解压,解压后的文件进入内存
  4. 关闭掉为解压创建的缓存
AssetBundle bundle = www.assetBundle;
  1. AssetBundle此时相当于一个桥梁,从Web Stream解压后的文件到最后实例化创建的对象之间的桥梁。
  2. 所以AssetBundle实质上是Web Stream解压后的文件中各个对象的映射。而非真实的对象。
  3. 实际的资源还存在Web Stream中,所以此时要保留Web Stream。
Instantiate(bundle.mainAsset);
  1. 通过AssetBundle获取资源,实例化对象

最后各位可能看到了官网中的这个例子使用了:

using(WWW www = WWW.LoadFromCacheOrDownload (BundleURL, version)){
}

这种using的用法。这种用法其实就是为了在使用完Web Stream之后,将内存释放掉的。因为WWW也继承了idispose的接口,所以可以使用using的这种用法。其实相当于最后执行了:

//删除Web Stream
www.Dispose();

OK,Web Stream被删除掉了。那还有谁呢?对Assetbundle。那么使用

//删除AssetBundle
bundle.Unload(false);

ok,写到这里就先打住啦。写的有点超了。有点赶也有点临时,日后在补充编辑。

更新,使用Unity Profiler工具检测内存

这篇文章当时写的时候略显仓促,因此并没有特别介绍Unity Profiler工具,也更谈不上用Unity Profiler工具来监测内存的使用状态了。但是使用Unity Profiler工具来监测还是十分必要的,下面就简单补充一下这方面的知识。

在Profiler工具中提供了两种模式供我们监测内存的使用情况,即简易模式和详细模式。在简易模式中,我们可以看到总的内存(total)列出了两列,即Used Total(使用总内存)Reserved Total(预定总内存)。Used Total和Reserved 均是物理内存,其中Reserved是unity向系统申请的总内存,Unity底层为了不经常向系统申请开辟内存,开启了较大一块内存作为缓存,即所谓的Reserved内存,而运行时,unity所使用的内存首先是向Reserved中来申请内存,当不使用时也是先向Reserved中释放内存,从而来保证游戏运行的流畅性。一般来说,Used Total越大,则Reserved Total越大,而当Used Total降下去后,Reserved Total也是会随之下降的(但并不一定与Used Total同步)。

Unity3D的内存从大体上可以分为以下几个部分:

  1. Unity:位Unity3D的底层代码所分配的内存。
  2. Mono:即托管堆。Mono运行时在运行游戏脚本时所需要的内存,换句话说托管堆的大小与我们的GameObject数量、资源量无关,仅是脚本代码造成的。这部分内存是有垃圾回收机制的。
  3. GfxDriver:可以理解为GPU显存开销,主要由Texture,Vertex buffer以及index buffer组成。所以尽可能地减少或释放Texture和mesh等资源,即可降低GfxDriver内存。
  4. FMOD:音频的内存开销。
  5. Profiler

而在简易模式下的监视器最下方,则列出了常见的一些资源以及它们所消耗的内存。

  1. 纹理
  2. 网格
  3. 材质
  4. 动作
  5. 音频
  6. 游戏对象的数量

而详细模式则需要点击“Take Sample”按钮来捕获详细的内存使用情况。需要注意的是,由于获得数据需要花费一定的时间,因此我们无法获得实时的详细内存的使用情况。在详细模式中,我们可以观察每个具体资源和游戏对象的内存使用情况。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!