首页 >Unity3D频道 >【Unity3D拓展编辑器】 > Unity3D研究院编辑器之ManagedStaticReferences()静态引用(二十九)
2017
05-30

Unity3D研究院编辑器之ManagedStaticReferences()静态引用(二十九)

Unity的Profiler可以看出来内存,但是遇到ManagedStaticReferences()估计大家都跪了。因为这个资源被静态引用了,然后我们并不知道它被哪里静态引用了。

我想了个办法,可以通过反射来查询它。先讲一下原理

1.反射dll

2.遍历所有的.cs 取出所有带static的属性。

3.对static下的所有属性以及子属性进行深度遍历,最终即可得出来被静态引用的资源。

如下代码所示,运行环境unity5.2.2

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.Reflection;
using System;
using System.Text;

public partial class ReportAsset
{

    static HashSet<object> s_Check;
    [MenuItem("Tools/Report/脚本Static引用")]
    static void StaticRef()
    {
        s_Check = new HashSet<object>();//避免被循环引用导致递归
        //静态引用
        LoadAssembly("Assembly-CSharp-firstpass");
        LoadAssembly("Assembly-CSharp");

    }

    static void LoadAssembly(string name)
    {
        Assembly assembly = null;
        try
        {
            assembly = Assembly.Load(name);
        }
        catch (Exception ex)
        {
            Debug.LogWarning(ex.Message);
        }
        finally
        {
            if (assembly != null)
            {
                foreach (Type type in assembly.GetTypes())
                {
                    try
                    {
                        HashSet<string> assetPaths = new HashSet<string>();
                        FieldInfo[] listFieldInfo = type.GetFields(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
                        foreach (FieldInfo fieldInfo in listFieldInfo)
                        {
                            if (!fieldInfo.FieldType.IsValueType)
                            {
                                SearchProperties(fieldInfo.GetValue(null), assetPaths);
                            }
                        }
                        if (assetPaths.Count > 0)
                        {
                            StringBuilder sb = new StringBuilder();
                            sb.AppendFormat("{0}.csn", type.ToString());
                            foreach (string path in assetPaths)
                            {
                                sb.AppendFormat("t{0}n", path);
                            }
                            Debug.LogError(sb.ToString());
                        }

                    }
                    catch (Exception ex)
                    {
                        Debug.LogWarning(ex.Message);
                    }
                }
            }
        }
    }

    static HashSet<string> SearchProperties(object obj, HashSet<string> assetPaths)
    {
        if (obj != null && s_Check.Add(obj))
        {
            if (obj is UnityEngine.Object)
            {
                UnityEngine.Object[] depen = EditorUtility.CollectDependencies(new UnityEngine.Object[] { obj as UnityEngine.Object });
                foreach (var item in depen)
                {
                    string assetPath = AssetDatabase.GetAssetPath(item);
                    if (!string.IsNullOrEmpty(assetPath))
                    {
                        assetPaths.Add(assetPath);
                    }
                }
            }
            else if (obj is IEnumerable)
            {
                foreach (object child in (obj as IEnumerable))
                {
                    SearchProperties(child, assetPaths);
                }
            }
            else if (obj is System.Object)
            {
                if (!obj.GetType().IsValueType)
                {
                    FieldInfo[] fieldInfos = obj.GetType().GetFields();
                    foreach (FieldInfo fieldInfo in fieldInfos)
                    {
                        object o = fieldInfo.GetValue(obj);
                        if (o != obj)
                        {
                            SearchProperties(fieldInfo.GetValue(obj), assetPaths);
                        }
                    }
                }
            }
        }
        return assetPaths;
    }

}

如下图所示,静态引用已经查出来了。
Snip20170530_1

问题:

1.这个脚本查不出lua里的静态引用。lua可以遍历G里的所有table表,和上面执行类型的操作就可以查出来。

2.如果想定向查询,比如专门查某一个资源在内存中哪里被引用,也和上面算法差不多改改就可以。

3.Unity在Editor下的Profiler其实是非常不准确的,因为自己在Project视图中选择一些资源unity也会记录在Profiler中,并且没办法完全清除。如果想测试内存,可以打一个pc包在连上Profiler在看即可。

最后,如果大家有更好的方法,欢迎再下面给我留言,我们一起讨论~

最后编辑:
作者:雨松MOMO
专注移动互联网,Unity3D游戏开发
捐 赠写博客不易,如果您想请我喝一杯星巴克的话?就进来看吧!

Unity3D研究院编辑器之ManagedStaticReferences()静态引用(二十九)》有 5 条评论

  1. peakcoder说:

    代码递归退出条件少了一条,环形引用的话,会导致堆栈溢出,untiy直接crash了

  2. boboshu说:

    我这边项目 泄露的还是查不出来……

留下一个回复

你的email不会被公开。 必填项已用 * 标注。