Search Unity

Estimate android asset bundle memory allocation

Discussion in 'Asset Bundles' started by KuratorIsPrimary, Jul 1, 2019.

  1. KuratorIsPrimary

    KuratorIsPrimary

    Joined:
    Dec 12, 2018
    Posts:
    6
    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<Type, float>

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

    Code (CSharp):
    1. [CustomEditor(typeof(LoadBundle))]
    2. public class LoadBundleEditor: Editor
    3. {
    4.     public string BundleName;
    5.  
    6.     private AssetBundle _bundle;
    7.     private GameObject _prefab;
    8.     private Dictionary<Type, float> TotalMemory = new Dictionary<Type, float>();
    9.     List<string> PreloadedObjects = new List<string>();
    10.     public override void OnInspectorGUI()
    11.     {
    12.         DrawDefaultInspector();
    13.  
    14.         if (GUILayout.Button("Load Bundle"))
    15.         {
    16.             LoadBundle loader = (LoadBundle)target;
    17.             EditorCoroutineUtility.StartCoroutine(LoadPrefabRequest(loader.BundleName + ".bundle"), this);
    18.         }
    19.     }
    20.  
    21.  
    22.     public IEnumerator LoadPrefabRequest(string bundleStr)
    23.     {
    24.         if (_bundle != null)
    25.         {
    26.             _bundle.Unload(true);
    27.             yield return null;
    28.         }
    29.  
    30.         TotalMemory.Clear();
    31.         PreloadedObjects.Clear();
    32.         AssetBundle bundle = AssetBundle.LoadFromFile(Path.Combine(Application.streamingAssetsPath, bundleStr));
    33.  
    34.         bundle.LoadAllAssets();
    35.         _bundle = bundle;
    36.  
    37.         yield return null;
    38.         float total = 0;
    39.         SerializedObject sBundle = new SerializedObject(bundle);
    40.  
    41.  
    42.         SerializedProperty allAssets = sBundle.FindProperty("m_PreloadTable");
    43.         foreach (SerializedProperty asset in allAssets)
    44.         {
    45.             if (asset.objectReferenceValue != null)
    46.             {
    47.                 float size = GetAssetSize(asset, asset.objectReferenceValue.GetType());
    48.                 if (PreloadedObjects.Contains(asset.objectReferenceValue.name + size))
    49.                     continue;
    50.                 if (TotalMemory.ContainsKey(asset.objectReferenceValue.GetType()))
    51.                 {
    52.                     TotalMemory[asset.objectReferenceValue.GetType()] += size;
    53.                 }
    54.                 else
    55.                 {
    56.                     TotalMemory.Add(asset.objectReferenceValue.GetType(), size);
    57.                 }
    58.                 PreloadedObjects.Add(asset.objectReferenceValue.name + size);
    59.             }
    60.         }
    61.  
    62.         foreach (KeyValuePair<Type, float> key in TotalMemory)
    63.         {
    64.             total += key.Value;
    65.             Debug.Log(key.Key + "<color=blue> memory should be: </color>" + key.Value / 1048576f);
    66.         }
    67.  
    68.         Debug.Log("<color=green> Total memory should be: </color>" + (total / 1048576f));
    69.     }
    70.  
    71.     float GetAssetSize(SerializedProperty s, Type t)
    72.     {
    73.         float mem = Profiler.GetRuntimeMemorySizeLong(s.objectReferenceValue);
    74.    
    75.  
    76.         return mem;
    77.     }
    78.     public float GetTextureSize(SerializedProperty s)
    79.     {
    80.         float mem = Profiler.GetRuntimeMemorySizeLong((Texture2D)s.objectReferenceValue);
    81.         Debug.Log("<color=cyan> Texture size of " + s.objectReferenceValue.name + " is </color>" + mem);
    82.         return mem;
    83.     }
    84. }
    In the end I show the memory of each Type as well as the Total Memory of that bundle. just like in the Profiler if you take a snapshot.

    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.
     
    Last edited: Jul 1, 2019
  2. KuratorIsPrimary

    KuratorIsPrimary

    Joined:
    Dec 12, 2018
    Posts:
    6
    Here are also two screenshots detailing the memory usage after loading "The Same" bundle in both Editor and on a connected Android. i'm focusing on textures as it is there where i'm having inconsistencies.

    Editor Snapshot: (Console + Memory profiler)
    EditorDetails.png

    Texture size shown is pretty much similar, i also logged the texture compression format.

    and here on Android:

    AndroidDetail.png

    I don't know what could have happened under the hood, yes having less size is the goal. but i need to understand why this isn't the case in the editor.

    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.
     
    Last edited: Jul 1, 2019
    xdegtyarev likes this.