1
\$\begingroup\$

I'm working on a small tool on top of the Asset bundle browser to estimate how much size in RAM a bundle will take so I can put a hard limit / validation before a bundle is submitted to version control by artists.

My approach is to:

  1. Load a bundle using bundle.LoadAllAssets()

  2. Make a serialized object from bundle

  3. Access the serialized property "m_PreloadTable"

  4. loop through every objectReferenceValue

  5. Get it Type then size using Profiler.GetRuntimeMemorySizeLong(object)

  6. Adding that to a Dictionnary

Here is the full Editor Class if you want to do Tests:

[CustomEditor(typeof(LoadBundle))]
public class LoadBundleEditor: Editor
{
    public string BundleName;

    private AssetBundle _bundle;
    private GameObject _prefab;
    private Dictionary<Type, float> TotalMemory = new Dictionary<Type, float>();
    List<string> PreloadedObjects = new List<string>();
    public override void OnInspectorGUI()
    {
        DrawDefaultInspector();

        if (GUILayout.Button("Load Bundle"))
        {
            LoadBundle loader = (LoadBundle)target;
            EditorCoroutineUtility.StartCoroutine(LoadPrefabRequest(loader.BundleName + ".bundle"), this);
        }
    }


    public IEnumerator LoadPrefabRequest(string bundleStr)
    {
        if (_bundle != null)
        {
            _bundle.Unload(true);
            yield return null;
        }

        TotalMemory.Clear();
        PreloadedObjects.Clear();
        AssetBundle bundle = AssetBundle.LoadFromFile(Path.Combine(Application.streamingAssetsPath, bundleStr));

        bundle.LoadAllAssets();
        _bundle = bundle;

        yield return null;
        float total = 0;
        SerializedObject sBundle = new SerializedObject(bundle);


        SerializedProperty allAssets = sBundle.FindProperty("m_PreloadTable");
        foreach (SerializedProperty asset in allAssets)
        {
            if (asset.objectReferenceValue != null)
            {
                float size = GetAssetSize(asset, asset.objectReferenceValue.GetType());
                if (PreloadedObjects.Contains(asset.objectReferenceValue.name + size))
                    continue;
                if (TotalMemory.ContainsKey(asset.objectReferenceValue.GetType()))
                {
                    TotalMemory[asset.objectReferenceValue.GetType()] += size;
                }
                else
                {
                    TotalMemory.Add(asset.objectReferenceValue.GetType(), size);
                }
                PreloadedObjects.Add(asset.objectReferenceValue.name + size);
            }
        }

        foreach (KeyValuePair<Type, float> key in TotalMemory)
        {
            total += key.Value;
            Debug.Log(key.Key + "<color=blue> memory should be: </color>" + key.Value / 1048576f);
        }

        Debug.Log("<color=green> Total memory should be: </color>" + (total / 1048576f));
    }

    float GetAssetSize(SerializedProperty s, Type t)
    {
        float mem = Profiler.GetRuntimeMemorySizeLong(s.objectReferenceValue);


        return mem;
    }
    public float GetTextureSize(SerializedProperty s)
    {
        float mem = Profiler.GetRuntimeMemorySizeLong((Texture2D)s.objectReferenceValue);
        Debug.Log("<color=cyan> Texture size of " + s.objectReferenceValue.name + " is </color>" + mem);
        return mem;
    }
}

In the end I show the memory of each Type as well as the Total Memory of that bundle.

I do a comparison by loading an AssetBundle in an empty APK project in Android and taking a Memory snapshot from the profiler. then I compare that data with my Editor tool by loading the same bundle file (and also checking an editor memory snapshot to see file sizes if they correspond).

And the values are different, In the Editor it feels like if i'm loading a Desktop bundle and not an Android one. Although the asset files are android ones, and the test unity project is set to Android. I tested on some UI bundles that don't have overrides for android and it works perfectly.

Do you have any idea how Unity behaves under the hood concerning assetbundles loading in the editor ?

Thanks.

Update: I found that the inconsistencies between the texture sizes only concern those that are compressed in ETC2_RGBA8 (size in editor is 4 times the size of their mobile counterpart), Size of those compressed using ETC_RGB4 are of the same size in both platforms.

Here are two screenshots of a Memory profiler of both Editor and Android after loading the same bundle.

Editor: enter image description here

Android: enter image description here

\$\endgroup\$
  • 1
    \$\begingroup\$ Can you give us some concrete examples of cases where your tool under/over-estimates Texture2D sizes? These details can help users work with you to track down the bug, even if they've never made such a tool before. \$\endgroup\$ – DMGregory Jun 30 '19 at 12:13
  • \$\begingroup\$ Edited the question by adding the full class, fixed also a small bug that gave wrong numbers and clarified my real question. \$\endgroup\$ – Omar Guendeli Jul 1 '19 at 6:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.