技术分享连载(三十一)

技术分享连载(三十一)

本期话题:如何清理NGUI的图集在内存中多存的部分、Profiler中Not Saved是指什么...精选5个资源优化问题,建议阅读时间10分钟,认真读完必有收获。如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。

UWA 问答社区:answer.uwa4d.com
UWA QQ群2:793972859(原群已满员)


资源管理

Q1:NGUI的图集在内存里存了多份,求问怎么清理?
请输入图片描述

游戏运行中,UI Mesh出现多份不同内存的情况,是正常的,因为随着UI widget使用的增加或减少,创建的UI Mesh是会随着变化的。同时,如果不同UIPanel中存在相同Atlas的Widgets,则也会出现上图中的情况。因此,建议大家遇到这种情况时,查看单帧中NGUI UI Mesh重名的是否有多份重名资源。如果存在,则说明相同Atlas中的资源被多个不同的UIPanel所使用,这种情况是需要尽可能避免的。
请输入图片描述


资源管理

Q2:Profiler中Not Saved是指什么?
请输入图片描述

Profiler中的Not Saved指的是项目中通过代码生成的各种资源记录。如上图所示,其Mesh均为NGUI插件通过脚本生成的UI界面Mesh资源。


资源管理

Q3:我已经下载了Shader,放到Unity里了,理应是不会自己引用,可是为什么还有如下这么多重复引用呢?
1. Mobile/Particles/Additive
2. Particles/Alpha Blended
3. Mobile/Particles/Alpha Blended
4. Default-Material

请输入图片描述

我们在Unity5.3.4版本上进行了测试,发现了以下两种情况:
.

  1. 对于Standard Shader来说,仅下载Shader确实是关联不上的。原因是Prefab上还用了Default-Material,这个也是Built-in资源,所以才会出现了Standard Shader的冗余问题。

请输入图片描述

. 上图可以直接看到这两个资源是同时出现,且均为冗余资源。对此,建议开发团队直接生成一个新的Material来代替Default-Material。
.

  1. 其他Shader关联不上的原因可能是:新下载Shader的GUID与项目中原始资源关联的GUID不一致,如下图所示。对此,大家需要自行对Meta文件中的相关GUID进行修改,将原始GUID替换为新下载Shader的GUID。最下方为一个批量处理该类问题的脚本代码,感谢QQ讨论群中网友wupei的提供!
    .
    请输入图片描述
using UnityEngine;
using System.Collections;
using UnityEditor;
using System.IO;

public class BuildScript {

    [MenuItem("Build/RefreshMat", false, 501)]
    static void RefreshMat() {
        var guids = AssetDatabase.FindAssets("t:Material");
        foreach (var guid in guids) {
            var path = AssetDatabase.GUIDToAssetPath(guid);
            if (path.ToLower().EndsWith("mat")) {
                var mat = AssetDatabase.LoadAssetAtPath<Material>(path);
                if (mat && mat.shader) {
                    Debugger.Log("{0}\n{1}\n{2}\n{3}\n", path, mat.shader.name,
                        mat.shader.GetInstanceID(),
                        Shader.Find(mat.shader.name).GetInstanceID());
                    mat.shader = Shader.Find(mat.shader.name);
                }
            }
        }
    }

}

资源管理

Q4: 我们测试了下发现,在名为A的MonoBehaviour中,有个数组来存放名为B的 MonoBehaviour对象的引用。当我们其他的逻辑去Destroy了B对象所在的GameObject后,在A对象中的数组里,遍历打印,它们(B的引用)都为Null,在Inspector面板上看是missing。而这时候进行GC,堆内存其实并未释放这些B对象。只有当A对象中的数组被清空后,再调用GC,才可释放这些对象所占内存。这种现象是否正常?为什么值为Null但却还是被引用着,无法通过GC释放呢?

首先这种现象是正常的。这是Unity中对Null的检测做了特殊的处理所致,在Unity中MonoBehaviour对象除了存在于Managed Heap中(作为“壳”),在Native内存中还会有一个相对应的“实体”,在调用Destroy时,真正被释放的正是这个“实体”。而在判断一个MonoBehaviour对象是否为Null时,Unity会首先检测“实体”是否已经被销毁,如果是则返回为true,但此时Managed Heap中的“壳”实际上依然是被引用的,从而就会出现对象的Null判断为true,但实际上还是被引用着,无法被GC释放的问题。
.
相关的细节可见官方blog对Unity中Null判断的解释:
http://blogs.unity3d.com/2014/05/16/custom-operator-should-we-keep-it/


资源管理

Q5:Optimize Game Objects对于老版本的Animation系统有没有作用呢?

没有作用。Optimize Game Objects功能是Unity4.3版本推出的功能,且仅对Mecanim动画系统起作用。如果可以的话,建议研发团队尽可能使用Mecanim来作为项目动画系统的解决方案。


【技术分享】是UWA推出的技术交流栏目,我们会定期将开发团队中反馈的常见问题加以总结并梳理在此,以供大家参考。