Search Unity

Query the amount of heap used during runtime?

Discussion in 'Web' started by cjddmut, Oct 21, 2016.

  1. cjddmut

    cjddmut

    Joined:
    Nov 19, 2012
    Posts:
    179
    In order to get our game's memory usage to 256mb, I needed to space out all initialization across several frames (to avoid spiking over 256mb before the garbage collector can run in webgl). This works quite awesomely! I can preload the entire game (I do love my object pooling) over some number of seconds/frames.

    However, this falls apart if the player switches to a different tab while the game is loading. I already have Application.runInBackground set to true and I can tell in the console that we do indeed have frames that are executing but they are very very slow, to the order of one frame every second or two. If I need 100+ frames to load my game this is almost feels like it pauses (as opposed to spinning very fast if the tab is active).

    I understand that the browser will/can throttle the CPU, especially if it is tabbed away, but this seems unrelated. If I try to load as much I can in the slow frames I can actually load quite a lot but I'll spike over the memory limit which defeats the purpose what I'm trying to accomplish.

    So either I need some tips on another way to accomplish loading my game while keeping the memory under 256mb or I need to get clever and load as much as I can in the given frame if the browser is tabbed away. If I could query how much of the heap is currently being used then I could bail once I start approaching the limit and wait til the next frame to continue.

    So long story short, how can I query the heap currently being used in the webgl memory allocation?

    *EDIT* Or if I can tell unity to just try to spin as fast as it can even if the browser is tabbed away.
     
  2. cjddmut

    cjddmut

    Joined:
    Nov 19, 2012
    Posts:
    179
  3. cjddmut

    cjddmut

    Joined:
    Nov 19, 2012
    Posts:
    179
    I found a good enough solution for my end. I yield every time System.GC.GetTotalMemory() exceeds a certain value (in my case 128mb).

    Though I don't fully understand what System.GC.GetTotalMemory() represents in the WebGL build? Is it the memory that's been allocated by mono (so all my MonoBehaviour logic and garbage)? If I could get some insight into that it would be great.

    Thanks
     
  4. Marco-Trivellato

    Marco-Trivellato

    Unity Technologies

    Joined:
    Jul 9, 2013
    Posts:
    1,654
  5. yoyobbi

    yoyobbi

    Joined:
    Nov 26, 2013
    Posts:
    16
    It appears that GC.GetTotalMemory is at best an approximation. The following code generally comes up with a difference of zero bytes, suggesting that perhaps managed memory is allocated and reported in chunks, and if a new chunk is not required, no additional memory is "allocated", at least from the perspective of GetTotalMemory. (I'm running this code in the Editor environment with Unity 5.4.3f1). I also tried passing "true" to force a garbage collection, and also made sure to reference the contents of the allocated array after the GetTotalMemory call to make sure it hadn't been optimized away or already collected.

    long before = System.GC.GetTotalMemory(false);
    int[] ints = new int[8];
    long after = System.GC.GetTotalMemory(false);
    long diff = after - before;
    Debug.Log("allocated bytes=" + diff.ToString());

    Note that running equivalent code in a small .NET application on a Windows PC does reveal granular changes in allocated memory, as expected for the size of the allocated objects.


    More investigation to come.
     
    sirshelley likes this.
  6. yoyobbi

    yoyobbi

    Joined:
    Nov 26, 2013
    Posts:
    16
    More investigation indicates that memory is reserved in multiples of 4K (4096 bytes). The attached test program allocates blocks of memory and calculates the GC.GetTotalMemory difference between successive allocations. The measured diffs are always multiples of 4096, no matter what size blocks are allocated.

    It appears that the overhead of allocating a byte array is 40 bytes -- if I allocate "new byte[4096]" then GetTotalMemory shows an increase in reserved memory of 8192, but "new byte[4096 - 40]" reserves just 4096 (and "new byte[4096 - 40 + 1]" reserves 8192).

    I have tested this with Unity 5.4.3f1, in the Unity Editor at edit time and play time and in a standalone 64-bit Windows build. Results are consistent in all scenarios.

    To try it for yourself, add the attached script to a current or new Unity project, create an empty scene and add the attached component to the main camera (or any other object in the scene). You can edit the block size and count and click the TestTotalMemory button to run the test. At edit time there is also an Inspector context menu to run the test.

    GetTotalMemoryTest script also added to the Unify wiki.
     

    Attached Files:

    Last edited: Dec 23, 2016
  7. andyz

    andyz

    Joined:
    Jan 5, 2010
    Posts:
    2,268
    If I call System.GC.GetTotalMemory to display memory usage in my webgl app it shows only 5mb, yet it needs 1gb of memory allocation to run without complaining about memory!

    So what exactly is it displaying - does it include all memory allocated for assets or just the managed code heap?

    How could I measure actual memory usage of my app in terms of the scene and textures/models?
     
  8. Marco-Trivellato

    Marco-Trivellato

    Unity Technologies

    Joined:
    Jul 9, 2013
    Posts:
    1,654
    this blog post should clarify System.GC.GetTotalMemory() and how to know how much memory is used inside the Unity Heap.
     
    guneyozsan, futurlab_xbox and andyz like this.
  9. andyz

    andyz

    Joined:
    Jan 5, 2010
    Posts:
    2,268
    Thanks, though would be good if a lot of that info was added to the manual and kept up to date.

    Profiling is tricky though if you can not attach to the webgl content as:
    - it means you have to do a full build and run every time to use it which is extremely slow (no 'run without re-build' even?)
    - I can not test load my asset bundles because I am not running on the right domain.
     
  10. andyz

    andyz

    Joined:
    Jan 5, 2010
    Posts:
    2,268
    For anyone wanting to check their webgl memory use I urge you to check the blog post Marco links to above (https://blogs.unity3d.com/2016/12/05/unity-webgl-memory-the-unity-heap/) and use the js code finally mentioned near the bottom (see GetDynamicMemorySize).
    This is so useful it should be integrated and put in the manual rather than being hidden in a blog post!

    (also profile your code for bad GC hits)
     
    guneyozsan likes this.