Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

How does Web Assembly deal with memory in general ?

Discussion in 'Web' started by ammar_12435, Feb 11, 2020.

  1. ammar_12435

    ammar_12435

    Joined:
    Jun 28, 2018
    Posts:
    24
    Hi!

    We are considering shifting from asm.js to Web Assembly (wasm) (Unity 2018.2.14f1)

    What we are concerned about is how wasm deals with memory (to avoid running out of memory errors). We have gone through most wasm unity blogs and posts, however a few things are still unclear:

    1- In asm.js, Unity's blogs stated that the content required a contiguous block of memory (the heap we request in Player settings). Does wasm also use contiguous blocks?

    2- Unity blogs state that in wasm, the heap size keeps on increasing as it is needed. By what factor does it increase each time, 2x?

    3- Unity blogs state that in wasm, the heap size keeps on increasing as it is needed. Is it possible to set a maximum limit till which we want the heap to grow automatically? Does the following emscripten argument do that:

    PlayerSettings.WebGL.emscriptenArgs = "-s WASM_MEM_MAX=512MB";


    4- Unity blogs state that in wasm, the heap size keeps on increasing as it is needed. Is it possible to set a starting heap size from which the heap size can keep on growing?

    Using asm.js, we needed 435 mb total heap memory for our content to run. Without any min and max limits, wasm increases the total heap memory to 536 mb where 170 mb is free (and hence waste). Any suggestions for this?

    Would be very grateful if you can answer as many of the above as possible.

    Thanks.
     
    CBHM likes this.
  2. alexsuvorov

    alexsuvorov

    Unity Technologies

    Joined:
    Nov 15, 2015
    Posts:
    327
    Hello ammar_12435.
    Yes, WebAssembly memory is allocated as a contiguous block.

    In latest Unity versions, and in Unity 2020.1 in particular, the algorithm is the following. If the current memory size is less or equal to 512MB, then the size of the heap doubles. If the current memory size is larger than 512MB, then it is gradually increased towards 2GB using the following formula 0.75 * currentMemorySize + 0.25 * 2GB. This means that it is getting closer and closer to 2GB but never reaches it, as heap size over 2GB is currently not supported (https://bugzilla.mozilla.org/show_bug.cgi?id=1392234)

    Yes, "-s WASM_MEM_MAX=512MB" will set the maximum size of the heap to 512MB. Note that if you run over this limit, your build will crash. WASM_MEM_MAX is used in situations where heap should not be resized, for example, for multi-threaded builds.

    Yes, you can achieve this using:
    Code (CSharp):
    1. PlayerSettings.WebGL.emscriptenArgs = "-s TOTAL_MEMORY=32MB"
    You can try the following:
    Code (CSharp):
    1. PlayerSettings.WebGL.emscriptenArgs = "-s TOTAL_MEMORY=55MB"
    After 3 resize iterations your heap will raise up to 55MB * 2 * 2 * 2 = 440MB.
     
    Last edited: Feb 11, 2020
    dongch007 and xeniaeo like this.
  3. ammar_12435

    ammar_12435

    Joined:
    Jun 28, 2018
    Posts:
    24
    Thank you for the detailed answer to all my questions! That is enormously helpful.
     
  4. ammar_12435

    ammar_12435

    Joined:
    Jun 28, 2018
    Posts:
    24
    The emscripten arguments are working quite as expected but there is a small ambiguity.

    If for instance I set:

    PlayerSettings.WebGL.emscriptenArgs = "-s [ICODE]TOTAL_MEMORY=55MB"


    The total memory wasm allocates in the start is 67MB. Why does it allocate an additional 12 mb?

    I tested with different values and here are the results in the format (set value, actual value):
    1- (55 MB,67 MB)
    2- (43 MB, 50 MB)
    3- (435 MB, 469 MB)

    From what I have observed,
    TOTAL_MEMORY
    sets a little MB's more than what we intend and that value is not constant.
     
    Jamesarndt2018 likes this.
  5. Eldamir88

    Eldamir88

    Joined:
    Jul 2, 2019
    Posts:
    12
    Hi,

    I'm a little late to this party. I've been around all the links and Github threads and Unity docs.

    As far as I gather, browsers are only now slowly trying to move towards allowing for allocations > 2GB. Great.

    In unity however, My experience was:

    - Set emscripten args with SetPlayerProperty
    - No, that is obsolete, use the explicit API, e.g. PlayerSettings.WebGL.emscriptenArgs = "-s ALLOW_MEMORY_GROWTH=1";
    - No, that has no effect, it seems. At least doesn't allow me to go over 2GB. Also, `emscriptenArgs` is undocumented (https://docs.unity3d.com/ScriptReference/PlayerSettings.WebGL.html), though there is PlayerSettings.WebGL.memorySize. Interesting
    - No, that setting is deprecated and has no effect at all (https://docs.unity3d.com/ScriptReference/PlayerSettings.WebGL-memorySize.html)
    - Ultimately, I am circled back to the following: https://docs.unity3d.com/Manual/webgl-memory.html , which basically says: "You want memory control. Well sorry, you can't have that".

    All in all, a frustrating research experience. A lot of outdated information out there :(

    For now it seems, there is no way for me to get >2GB allocated in WebGL builds, and I'll have to just live with that. Please, oh please, let me know if I'm mistaken.
     
  6. jukka_j

    jukka_j

    Unity Technologies

    Joined:
    May 4, 2018
    Posts:
    953
    SetPlayerProperty is indeed obsolete for setting Emscripten args. If there is an official manual documentation that refers to this, please let us know.

    It is unfortunate that forum posts go out of date like this.

    The explicit `PlayerSettings.WebGL.emscriptenArgs` API is the current method that is supported.

    PlayerSettings.WebGL.emscriptenArgs = "-s ALLOW_MEMORY_GROWTH=1"; did not seem to have an effect, because ALLOW_MEMORY_GROWTH=1 is actually the default enabled option. If you wanted to disable memory growth, you could set "-s ALLOW_MEMORY_GROWTH=0".

    Thanks for pointing that out. I think at some point the intent of emscriptenArgs has been to be an internal workaround tool, and to some extent, it still is. Added a note to add docs for this, it should be mentioned there.

    When ALLOW_MEMORY_GROWTH=1 is in effect, then memorySize specifies the initial heap size at startup, but it can freely grow at runtime. So practically it no longer has an effect.

    Marked down a note to update the docs on memorySize to explain this.

    That is unfortunately true. 2GB is the hard limit in Unity WebGL builds today, and also the hard limit in many web browsers today. Browsers have begun to work on 4GB support, but unfortunately it does not yet work in any browser.

    You can try that by running

    console.log(new Uint8Array(4*1024*1024*1024 - 65536).length);

    in your web browser developer console. If it prints an error, it means that 4GB WebAssembly heaps are not yet supported. Testing out today on Chrome and Firefox on Windows, neither can make it work. To test 2GB heap support, run

    console.log(new Uint8Array(2*1024*1024*1024 - 65536).length);

    which should print out 2147418112 if supported.
     
    xeniaeo and GilCat like this.
  7. jukka_j

    jukka_j

    Unity Technologies

    Joined:
    May 4, 2018
    Posts:
    953
    GilCat likes this.
  8. Black_Raptor

    Black_Raptor

    Joined:
    Nov 3, 2014
    Posts:
    182
    HI i got this error :
    stderr:ERROR:root:TOTAL_MEMORY must be larger than TOTAL_STACK, was 0 (TOTAL_STACK=5242880)


    I Try to increase the memory like that :
    Code (CSharp):
    1.    PlayerSettings.WebGL.emscriptenArgs = "-s ALLOW_MEMORY_GROWTH=1" + "-s TOTAL_MEMORY=35MB" + " -s ERROR_ON_UNDEFINED_SYMBOLS=0 " + emscriptenLinkerFlags;
    but that's not work, and i completly stuck :/
     
  9. De-Panther

    De-Panther

    Joined:
    Dec 27, 2009
    Posts:
    590
    "-s ALLOW_MEMORY_GROWTH=1" + "-s TOTAL_MEMORY=35MB" + " -s ERROR_ON_UNDEFINED_SYMBOLS=0 "
    is the same as:
    "-s ALLOW_MEMORY_GROWTH=1-s TOTAL_MEMORY=35MB -s ERROR_ON_UNDEFINED_SYMBOLS=0 "
    You missed some spaces in some parts...


    And Unity's default since 2019.x is to allow memory growth, so you should set it (to zero) only if you want to disable memory growth. I think that setting it to 1 will change nothing.
     
  10. Black_Raptor

    Black_Raptor

    Joined:
    Nov 3, 2014
    Posts:
    182
    Thanks, for your reply, i change to that :
    Code (CSharp):
    1. PlayerSettings.WebGL.emscriptenArgs = "-s TOTAL_MEMORY=35MB -s TOTAL_STACK=1MB " + emscriptenLinkerFlags;
    I can now compile without any error, but when i go to my browser he infinite load ... Before i make those script change, he load good, but give me an out of bound memory that's why i make those script
     
  11. Jeff-Kesselman

    Jeff-Kesselman

    Joined:
    Apr 5, 2010
    Posts:
    99
    In emscripten 1.9+ 4GB heaps are supported on V8 vms (Chrome, Edge, etc)

    Where is the 2GB limit and how can i change it to 4GB?
     
  12. Jeff-Kesselman

    Jeff-Kesselman

    Joined:
    Apr 5, 2010
    Posts:
    99
    SO... I found the constants in client.framework.js and changed them, but apparently the 2GB limti is built into the ELGS interface.

    So, as of today, it can't be done.

    This is a bug and shoudl be fixed. 2GB is really an untenable memory limit for a 3D program, especially one where it needs to load assets through that memory before they can get to the graphics card.


    Code (CSharp):
    1. Uncaught TypeError: WebGL2RenderingContext.bufferSubData: Argument 3 can't be an ArrayBuffer or an ArrayBufferView larger than 2 GB
    2.    _glBufferSubData https://localhost:5001/client/Build/client.framework.js:12459