1. We've introduced thread tags, search within a thread and similar thread search. Read more here.
    Dismiss Notice
  2. Learn how you'll soon be able to publish your games to China in four simple steps with Xiaomi. Sign up now for early access.
    Dismiss Notice
  3. Get further faster with the Unity Plus Accelerator Pack, free for new Unity Plus subscribers for a limited time. Click here for more details.
    Dismiss Notice
  4. We've released our first Timeline Experimental Preview, our new tool for creating cutscenes and more! To check it out click here.
    Dismiss Notice
  5. Unity 5.5 is now released.
    Dismiss Notice
  6. Check out all the fixes for 5.5 in patch releases 1 & 2.
    Dismiss Notice
  7. Unity 5.6 beta is now available for download.
    Dismiss Notice

Query the amount of heap used during runtime?

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

  1. cjddmut

    cjddmut

    Joined:
    Nov 19, 2012
    Posts:
    84
    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:
    84
  3. cjddmut

    cjddmut

    Joined:
    Nov 19, 2012
    Posts:
    84
    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:
    918
  5. yoyobbi

    yoyobbi

    Joined:
    Nov 26, 2013
    Posts:
    10
    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.
     
  6. yoyobbi

    yoyobbi

    Joined:
    Nov 26, 2013
    Posts:
    10
    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