aspnetcore: WebAssembly compilation fallback logic is wrong. May need some further docs about configuring memory limits.

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

I developed my own PWA application using Blazor. The app works normally on my computer and phone. But on my second phone the application doesn’t have time to load and an error appears. I connected my phone to the pc and through the chrome devtools I went to see the log on the console and I found the following errors.

Streaming compilation failed. Falling back to ArrayBuffer instantiation.  RangeError: WebAssembly.instantiate(): Out of memory: wasm memory

blazor.webassembly.js:1 TypeError: Failed to execute 'arrayBuffer' on 'Response': body stream already read
(anonymous)	@	blazor.webassembly.js:1
(anonymous)	@	blazor.webassembly.js:1
await in (anonymous) (async)		
(anonymous)	@	blazor.webassembly.js:1
createWasm	@	dotnet.6.0.2.hy3rmx5lfa.js:1
(anonymous)	@	dotnet.6.0.2.hy3rmx5lfa.js:1

blazor.webassembly.js:1 Uncaught (in promise) TypeError: Failed to execute 'arrayBuffer' on 'Response': body stream already read
    at blazor.webassembly.js:1:36928
    at async blazor.webassembly.js:1:36900
    at async blazor.webassembly.js:1:36636
(anonymous)	@	blazor.webassembly.js:1
await in (anonymous) (async)		
(anonymous)	@	blazor.webassembly.js:1
createWasm	@	dotnet.6.0.2.hy3rmx5lfa.js:1
(anonymous)	@	dotnet.6.0.2.hy3rmx5lfa.js:1

The PWA is distributed as AzureStaticApps. Some specifics about the phone having these problems:

  • Phone model: Samsung Galaxy J5 (2016)
  • Android version: 7.1.1
  • Chrome version: 98.0.3758.87
  • Edge version: 97.0.1702.78

I attach some photos of the console and network traffic

Schermata 2022-02-09 alle 11 09 33 Schermata 2022-02-09 alle 11 09 53 Schermata 2022-02-09 alle 11 10 04 Schermata 2022-02-09 alle 11 16 02

Expected Behavior

The PWA should work just as well as it does on the PC and other phones

Steps To Reproduce

Simply, create a PWA project and try it out on low-end phones.

Exceptions (if any)

No response

.NET Version

6.0.102

Anything else?

No response

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 3
  • Comments: 26 (14 by maintainers)

Commits related to this issue

Most upvoted comments

I discovered that my production deployment was using about 8x more memory than my local development instance for a total of 512MB, now add on top of this the refresh memory leak and it causes devices to go over 1GB.

Testing locally out of my visual studio debugger I could not reproduce the memory issue. So I set up a local IIS server and deployed to it with a local file publish process. With this IIS instance I was able to reproduce the 500MB issue. I then compared the output of the visual studio debug instance to the IIS published instance. I found that the generated _framework/dotnet.6.0.x.js files were substantially different and there the root of my problem:

image

looking into this INITIAL_MEMORY property I found some github forum posts saying that for Development environments it will default to 16777216 (16MB) and Production environments will default to 536870912 (512MB). Normally this is not a huge deal but with the Memory Leak in .NET 6 and chrome after refresh it is a major problem.

In C:\Program Files\dotnet\packs\Microsoft.NET.Runtime.WebAssembly.Sdk\6.0.4\Sdk\WasmApp.targets it says the following in the documentation section:

image

Knowing this, I then tried adding the referenced EmccTotalMemory property to my Blazor.Client csproject file.

<PropertyGroup> <TargetFramework>net6.0</TargetFramework> <EmccTotalMemory>16777216</EmccTotalMemory> </PropertyGroup>

I rebuilt and published to my local IIS site and thankfully the 512MB was now down to ~50MB. I then published to a public test instance and re-tested all of my failing devices and they are now all working great, even with the refresh memory leak because it goes from 50-60MB to 120MB instead of 512MB to 1GB.

@SteveSandersonMS For me anyway the priority of fixing this Refresh Memory Leak is reduced as I found the workaround to reduce total inital memory, but I feel it is still important to fix this sooner than later. This could be causing lots of random issues during app use, granted mostly for low end devices, but this is quite a bit of a difference from the total memory use of the same app running on .NET 5.

Additionally, I do not like the logic behind having 16MB for Development builds and 512MB as the initial memory size for Production. I get that you may want development instances to show “True Memory Usage” so it starts small and then auto expands to what it needs so Devs can more easily see what their app is utilizing. And I get that allocating memory on the fly might result in poorer performance, so for Production builds it auto allocates 512MB. However, to me this falls into the category of pre-optimization. I would rather that both my Development and Production instances behaved the same for memory allocation until I choose to optimize it. This difference in behavior caused a problem to only represent in a production instance with no natural way to diagnose it in a dev environment without tearing apart the OOB Microsoft publish process.

Anyway sorry for the book and hopefully if anyone else is running into this they can take the same steps as me to work around it for now.

@TanayParikh Thanks for confirming.

@mkArtakMSFT I’ve updated this issue title to reflect our newer understanding. This is something we should try to address in .NET 7 if we can, as it’s relatively cheap (~2 days I’d guess).

@TanayParikh Reading the comments above, it sounds like there are three separate issues:

  • In some cases people may have the wrong content-type on the .wasm response. Action: we should check the content-type, and not attempt streaming compilation if it’s wrong.
  • In other cases, even when the content-type is correct, the browser might give an OOM error during module instantiation. Action: we should try to get a repro of this, and figure out if there’s a way to change the compilation settings to set a different memory limit to fix it. If so, we can then document that solution, or even consider changing the default.
  • Regardless of all this, our fallback logic is nonsensical as it would never work. Action: stop attempting fallback - just use either streaming or non-streaming compilation based on the content-type.

What do you think? Does that match you interpretation?

I think following changes would be good:

  • if streaming failed, remove the file from cache so that mime-type could fix itself next time if it was cached wrong.
  • re-try the download without streaming with new request because body stream already read
  • surface the OOM error with better message
  • check response mime-type and provide better message if there is issue

Both changes should be done on Blazor repo. @danroth27 could you please move the issue.

Isn’t there already a solution about this dotnet/runtime#58569 ?

p.s I stumbled upon this open issue while looking for why .wasm files had wrong mime type for me, and the solution was to clear the cache storage manually in the browser.