[browser][coreCLR] reduce initial memory footprint - #127905

Merged
pavelsavara merged 1 commit into
dotnet:mainfrom
pavelsavara:INITIAL_MEMORY_STACK_SIZE_
May 9, 2026
Merged

[browser][coreCLR] reduce initial memory footprint#127905
pavelsavara merged 1 commit into
dotnet:mainfrom
pavelsavara:INITIAL_MEMORY_STACK_SIZE_

Conversation

@pavelsavara

@pavelsavarapavelsavara commented May 7, 2026

Copy link
Copy Markdown
Member

Fixes#127880

@pavelsavarapavelsavara added this to the 11.0.0 milestone May 7, 2026
@pavelsavarapavelsavara self-assigned this May 7, 2026
CopilotAI review requested due to automatic review settings May 7, 2026 08:10
@pavelsavarapavelsavara added arch-wasm WebAssembly architecture area-Host os-browser Browser variant of arch-wasm labels May 7, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to 'arch-wasm': @lewing, @pavelsavara
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reduces the default WebAssembly memory and stack settings used by the CoreCLR browser host, aiming to lower the initial memory footprint during startup (per #127880).

Changes:

  • Decrease Emscripten INITIAL_MEMORY from 128 MB to 32 MB for browserhost.
  • Decrease Emscripten STACK_SIZE from 5 MB to 2 MB for browserhost.
  • Keep the MSBuild CoreCLR WASM relink targets in sync with the browserhost CMake configuration.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

FileDescription
src/native/corehost/browserhost/CMakeLists.txtLowers default INITIAL_MEMORY and STACK_SIZE link options for the browser host to reduce startup footprint.
src/mono/browser/build/BrowserWasmApp.CoreCLR.targetsMirrors the updated memory/stack defaults in the CoreCLR WASM relink pipeline so app relinks match the host configuration.

@pavelsavara
pavelsavara marked this pull request as ready for review May 7, 2026 11:32

@radekdoulikradekdoulik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, let see if CI tests will pass. Thank you!

@jkotas

jkotas commented May 7, 2026

Copy link
Copy Markdown
Member

There are more places where this is hardcoded:

src\mono\browser\browser.proj(219):<EmccStackSize>5MB</EmccStackSize>
src\mono\browser\build\BrowserWasmApp.targets(171):<EmccStackSize Condition="'$(EmccStackSize)' == ''">5MB</EmccStackSize>
src\mono\wasm\build\WasmApp.Common.targets(67):- $(EmccStackSize) - Stack size. Default value: 5MB.

Is this inconsistency intentional?

@pavelsavara

Copy link
Copy Markdown
MemberAuthor

Is this inconsistency intentional?

Yes, that is Mono

@jkotas

Copy link
Copy Markdown
Member

What's the reasoning behind lower limits for CoreCLR? Is there a problem with applying the same lower limits to Mono as well?

@pavelsavara

pavelsavara commented May 8, 2026

Copy link
Copy Markdown
MemberAuthor

What's the reasoning behind lower limits for CoreCLR?

It's "see how low we can set it before things break".

STACK_SIZE is more interesting. We discussed with @davidwrighton that I saw some deep stack traces on the interpreter, but I don't remember where. He said that 2MB should be enough.
And we could possibly weed out some deep interp->native->interp transitions.
The build here is green so, we didn't find the bottom yet.

INITIAL_MEMORY is only about re-allocating the linear memory later, this will not break anything, but possibly make it bit slower to start if this value it too low. I want to see the impact on my macro benchmark. Current value is 128MB which none of the tested/compatible apps need and so currently we are not learning the actual low value from that.

The 32MB is matching Mono default value. I remember you said <20MB should be possible. Do you want to try that ?

Blazor template app uses 84MB large linear memory to start on this branch.

Is there a problem with applying the same lower limits to Mono as well?

STACK_SIZE was changed in #81215 but I don't remember why or what was the previous value.

Mono AOT in particular has big INITIAL_MEMORY footprint growing with size of the code. I think it's about some relocations or trampolines. The initial memory needs to be large enough so that some Mono AOT data segment could be applied by the engine at the initial load. There is dedicated MSBuild logic for calculating it. We may need same thing for R2R later.

Right now Mono is "don't touch it" territory.

@jkotas do you have specific concern or just curiosity ?

@jkotas

Copy link
Copy Markdown
Member

STACK_SIZE is more interesting.

Stack size is user observable. Smaller stack size should be better for perf, but it can break user apps. I think it is ok to change it for CoreCLR. It is a breaking change though. We may want to mention it in the Mono -> CoreCLR breaking change notice that we are going to file eventually.

I remember you said <20MB should be possible

This comment was about the GC heap size specifically. It was not about the total memory consumption.

do you have specific concern or just curiosity?

What is the user observable impact of this change? For example, do you see a smaller working set reported by the OS for a typical wasm app or test? Can this regress startup time for a typical wasm app? (I assume that the growing memory has some time overhead, hopefully it is neglible.)

You will always see me asking questions on perf-related PRs that do not have any numbers in the descriptions ;-)

@pavelsavara

Copy link
Copy Markdown
MemberAuthor

/ba-g known infra issue

@pavelsavara
pavelsavara merged commit 6b1231d into dotnet:mainMay 9, 2026
75 checks passed
@pavelsavara
pavelsavara deleted the INITIAL_MEMORY_STACK_SIZE_ branch May 9, 2026 10:04
@pavelsavara

Copy link
Copy Markdown
MemberAuthor

You will always see me asking questions on perf-related PRs that do not have any numbers in the descriptions ;-)

@jkotas we are getting there. Macrobenchmark can now run measurement on PR/branch.

It will take some time until the code flows thru VMR into preview builds.

imageimageimage

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

arch-wasmWebAssembly architecturearea-Hostos-browserBrowser variant of arch-wasm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[browser][coreCLR] reduce INITIAL_MEMORY and STACK_SIZE

5 participants

@pavelsavara@jkotas@radekdoulik@maraf
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

[browser][coreCLR] reduce initial memory footprint - #127905

Merged
pavelsavara merged 1 commit into
dotnet:mainfrom
pavelsavara:INITIAL_MEMORY_STACK_SIZE_
May 9, 2026
Merged

[browser][coreCLR] reduce initial memory footprint#127905
pavelsavara merged 1 commit into
dotnet:mainfrom
pavelsavara:INITIAL_MEMORY_STACK_SIZE_

Conversation

@pavelsavara

@pavelsavarapavelsavara commented May 7, 2026

Copy link
Copy Markdown
Member

Fixes#127880

@pavelsavarapavelsavara added this to the 11.0.0 milestone May 7, 2026
@pavelsavarapavelsavara self-assigned this May 7, 2026
CopilotAI review requested due to automatic review settings May 7, 2026 08:10
@pavelsavarapavelsavara added arch-wasm WebAssembly architecture area-Host os-browser Browser variant of arch-wasm labels May 7, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to 'arch-wasm': @lewing, @pavelsavara
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reduces the default WebAssembly memory and stack settings used by the CoreCLR browser host, aiming to lower the initial memory footprint during startup (per #127880).

Changes:

  • Decrease Emscripten INITIAL_MEMORY from 128 MB to 32 MB for browserhost.
  • Decrease Emscripten STACK_SIZE from 5 MB to 2 MB for browserhost.
  • Keep the MSBuild CoreCLR WASM relink targets in sync with the browserhost CMake configuration.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

FileDescription
src/native/corehost/browserhost/CMakeLists.txtLowers default INITIAL_MEMORY and STACK_SIZE link options for the browser host to reduce startup footprint.
src/mono/browser/build/BrowserWasmApp.CoreCLR.targetsMirrors the updated memory/stack defaults in the CoreCLR WASM relink pipeline so app relinks match the host configuration.

@pavelsavara
pavelsavara marked this pull request as ready for review May 7, 2026 11:32

@radekdoulikradekdoulik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, let see if CI tests will pass. Thank you!

@jkotas

jkotas commented May 7, 2026

Copy link
Copy Markdown
Member

There are more places where this is hardcoded:

src\mono\browser\browser.proj(219):<EmccStackSize>5MB</EmccStackSize>
src\mono\browser\build\BrowserWasmApp.targets(171):<EmccStackSize Condition="'$(EmccStackSize)' == ''">5MB</EmccStackSize>
src\mono\wasm\build\WasmApp.Common.targets(67):- $(EmccStackSize) - Stack size. Default value: 5MB.

Is this inconsistency intentional?

@pavelsavara

Copy link
Copy Markdown
MemberAuthor

Is this inconsistency intentional?

Yes, that is Mono

@jkotas

Copy link
Copy Markdown
Member

What's the reasoning behind lower limits for CoreCLR? Is there a problem with applying the same lower limits to Mono as well?

@pavelsavara

pavelsavara commented May 8, 2026

Copy link
Copy Markdown
MemberAuthor

What's the reasoning behind lower limits for CoreCLR?

It's "see how low we can set it before things break".

STACK_SIZE is more interesting. We discussed with @davidwrighton that I saw some deep stack traces on the interpreter, but I don't remember where. He said that 2MB should be enough.
And we could possibly weed out some deep interp->native->interp transitions.
The build here is green so, we didn't find the bottom yet.

INITIAL_MEMORY is only about re-allocating the linear memory later, this will not break anything, but possibly make it bit slower to start if this value it too low. I want to see the impact on my macro benchmark. Current value is 128MB which none of the tested/compatible apps need and so currently we are not learning the actual low value from that.

The 32MB is matching Mono default value. I remember you said <20MB should be possible. Do you want to try that ?

Blazor template app uses 84MB large linear memory to start on this branch.

Is there a problem with applying the same lower limits to Mono as well?

STACK_SIZE was changed in #81215 but I don't remember why or what was the previous value.

Mono AOT in particular has big INITIAL_MEMORY footprint growing with size of the code. I think it's about some relocations or trampolines. The initial memory needs to be large enough so that some Mono AOT data segment could be applied by the engine at the initial load. There is dedicated MSBuild logic for calculating it. We may need same thing for R2R later.

Right now Mono is "don't touch it" territory.

@jkotas do you have specific concern or just curiosity ?

@jkotas

Copy link
Copy Markdown
Member

STACK_SIZE is more interesting.

Stack size is user observable. Smaller stack size should be better for perf, but it can break user apps. I think it is ok to change it for CoreCLR. It is a breaking change though. We may want to mention it in the Mono -> CoreCLR breaking change notice that we are going to file eventually.

I remember you said <20MB should be possible

This comment was about the GC heap size specifically. It was not about the total memory consumption.

do you have specific concern or just curiosity?

What is the user observable impact of this change? For example, do you see a smaller working set reported by the OS for a typical wasm app or test? Can this regress startup time for a typical wasm app? (I assume that the growing memory has some time overhead, hopefully it is neglible.)

You will always see me asking questions on perf-related PRs that do not have any numbers in the descriptions ;-)

@pavelsavara

Copy link
Copy Markdown
MemberAuthor

/ba-g known infra issue

@pavelsavara
pavelsavara merged commit 6b1231d into dotnet:mainMay 9, 2026
75 checks passed
@pavelsavara
pavelsavara deleted the INITIAL_MEMORY_STACK_SIZE_ branch May 9, 2026 10:04
@pavelsavara

Copy link
Copy Markdown
MemberAuthor

You will always see me asking questions on perf-related PRs that do not have any numbers in the descriptions ;-)

@jkotas we are getting there. Macrobenchmark can now run measurement on PR/branch.

It will take some time until the code flows thru VMR into preview builds.

imageimageimage

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

arch-wasmWebAssembly architecturearea-Hostos-browserBrowser variant of arch-wasm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[browser][coreCLR] reduce INITIAL_MEMORY and STACK_SIZE

5 participants

@pavelsavara@jkotas@radekdoulik@maraf
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[browser][coreCLR] reduce initial memory footprint - #127905

Merged
pavelsavara merged 1 commit into
dotnet:mainfrom
pavelsavara:INITIAL_MEMORY_STACK_SIZE_
May 9, 2026
Merged

[browser][coreCLR] reduce initial memory footprint#127905
pavelsavara merged 1 commit into
dotnet:mainfrom
pavelsavara:INITIAL_MEMORY_STACK_SIZE_

Conversation

@pavelsavara

@pavelsavarapavelsavara commented May 7, 2026

Copy link
Copy Markdown
Member

Fixes#127880

@pavelsavarapavelsavara added this to the 11.0.0 milestone May 7, 2026
@pavelsavarapavelsavara self-assigned this May 7, 2026
CopilotAI review requested due to automatic review settings May 7, 2026 08:10
@pavelsavarapavelsavara added arch-wasm WebAssembly architecture area-Host os-browser Browser variant of arch-wasm labels May 7, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to 'arch-wasm': @lewing, @pavelsavara
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reduces the default WebAssembly memory and stack settings used by the CoreCLR browser host, aiming to lower the initial memory footprint during startup (per #127880).

Changes:

  • Decrease Emscripten INITIAL_MEMORY from 128 MB to 32 MB for browserhost.
  • Decrease Emscripten STACK_SIZE from 5 MB to 2 MB for browserhost.
  • Keep the MSBuild CoreCLR WASM relink targets in sync with the browserhost CMake configuration.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

FileDescription
src/native/corehost/browserhost/CMakeLists.txtLowers default INITIAL_MEMORY and STACK_SIZE link options for the browser host to reduce startup footprint.
src/mono/browser/build/BrowserWasmApp.CoreCLR.targetsMirrors the updated memory/stack defaults in the CoreCLR WASM relink pipeline so app relinks match the host configuration.

@pavelsavara
pavelsavara marked this pull request as ready for review May 7, 2026 11:32

@radekdoulikradekdoulik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, let see if CI tests will pass. Thank you!

@jkotas

jkotas commented May 7, 2026

Copy link
Copy Markdown
Member

There are more places where this is hardcoded:

src\mono\browser\browser.proj(219):<EmccStackSize>5MB</EmccStackSize>
src\mono\browser\build\BrowserWasmApp.targets(171):<EmccStackSize Condition="'$(EmccStackSize)' == ''">5MB</EmccStackSize>
src\mono\wasm\build\WasmApp.Common.targets(67):- $(EmccStackSize) - Stack size. Default value: 5MB.

Is this inconsistency intentional?

@pavelsavara

Copy link
Copy Markdown
MemberAuthor

Is this inconsistency intentional?

Yes, that is Mono

@jkotas

Copy link
Copy Markdown
Member

What's the reasoning behind lower limits for CoreCLR? Is there a problem with applying the same lower limits to Mono as well?

@pavelsavara

pavelsavara commented May 8, 2026

Copy link
Copy Markdown
MemberAuthor

What's the reasoning behind lower limits for CoreCLR?

It's "see how low we can set it before things break".

STACK_SIZE is more interesting. We discussed with @davidwrighton that I saw some deep stack traces on the interpreter, but I don't remember where. He said that 2MB should be enough.
And we could possibly weed out some deep interp->native->interp transitions.
The build here is green so, we didn't find the bottom yet.

INITIAL_MEMORY is only about re-allocating the linear memory later, this will not break anything, but possibly make it bit slower to start if this value it too low. I want to see the impact on my macro benchmark. Current value is 128MB which none of the tested/compatible apps need and so currently we are not learning the actual low value from that.

The 32MB is matching Mono default value. I remember you said <20MB should be possible. Do you want to try that ?

Blazor template app uses 84MB large linear memory to start on this branch.

Is there a problem with applying the same lower limits to Mono as well?

STACK_SIZE was changed in #81215 but I don't remember why or what was the previous value.

Mono AOT in particular has big INITIAL_MEMORY footprint growing with size of the code. I think it's about some relocations or trampolines. The initial memory needs to be large enough so that some Mono AOT data segment could be applied by the engine at the initial load. There is dedicated MSBuild logic for calculating it. We may need same thing for R2R later.

Right now Mono is "don't touch it" territory.

@jkotas do you have specific concern or just curiosity ?

@jkotas

Copy link
Copy Markdown
Member

STACK_SIZE is more interesting.

Stack size is user observable. Smaller stack size should be better for perf, but it can break user apps. I think it is ok to change it for CoreCLR. It is a breaking change though. We may want to mention it in the Mono -> CoreCLR breaking change notice that we are going to file eventually.

I remember you said <20MB should be possible

This comment was about the GC heap size specifically. It was not about the total memory consumption.

do you have specific concern or just curiosity?

What is the user observable impact of this change? For example, do you see a smaller working set reported by the OS for a typical wasm app or test? Can this regress startup time for a typical wasm app? (I assume that the growing memory has some time overhead, hopefully it is neglible.)

You will always see me asking questions on perf-related PRs that do not have any numbers in the descriptions ;-)

@pavelsavara

Copy link
Copy Markdown
MemberAuthor

/ba-g known infra issue

@pavelsavara
pavelsavara merged commit 6b1231d into dotnet:mainMay 9, 2026
75 checks passed
@pavelsavara
pavelsavara deleted the INITIAL_MEMORY_STACK_SIZE_ branch May 9, 2026 10:04
@pavelsavara

Copy link
Copy Markdown
MemberAuthor

You will always see me asking questions on perf-related PRs that do not have any numbers in the descriptions ;-)

@jkotas we are getting there. Macrobenchmark can now run measurement on PR/branch.

It will take some time until the code flows thru VMR into preview builds.

imageimageimage

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

arch-wasmWebAssembly architecturearea-Hostos-browserBrowser variant of arch-wasm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[browser][coreCLR] reduce INITIAL_MEMORY and STACK_SIZE

5 participants

@pavelsavara@jkotas@radekdoulik@maraf
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[browser][coreCLR] reduce initial memory footprint - #127905

Merged
pavelsavara merged 1 commit into
dotnet:mainfrom
pavelsavara:INITIAL_MEMORY_STACK_SIZE_
May 9, 2026
Merged

[browser][coreCLR] reduce initial memory footprint#127905
pavelsavara merged 1 commit into
dotnet:mainfrom
pavelsavara:INITIAL_MEMORY_STACK_SIZE_

Conversation

@pavelsavara

@pavelsavarapavelsavara commented May 7, 2026

Copy link
Copy Markdown
Member

Fixes#127880

@pavelsavarapavelsavara added this to the 11.0.0 milestone May 7, 2026
@pavelsavarapavelsavara self-assigned this May 7, 2026
CopilotAI review requested due to automatic review settings May 7, 2026 08:10
@pavelsavarapavelsavara added arch-wasm WebAssembly architecture area-Host os-browser Browser variant of arch-wasm labels May 7, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to 'arch-wasm': @lewing, @pavelsavara
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reduces the default WebAssembly memory and stack settings used by the CoreCLR browser host, aiming to lower the initial memory footprint during startup (per #127880).

Changes:

  • Decrease Emscripten INITIAL_MEMORY from 128 MB to 32 MB for browserhost.
  • Decrease Emscripten STACK_SIZE from 5 MB to 2 MB for browserhost.
  • Keep the MSBuild CoreCLR WASM relink targets in sync with the browserhost CMake configuration.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

FileDescription
src/native/corehost/browserhost/CMakeLists.txtLowers default INITIAL_MEMORY and STACK_SIZE link options for the browser host to reduce startup footprint.
src/mono/browser/build/BrowserWasmApp.CoreCLR.targetsMirrors the updated memory/stack defaults in the CoreCLR WASM relink pipeline so app relinks match the host configuration.

@pavelsavara
pavelsavara marked this pull request as ready for review May 7, 2026 11:32

@radekdoulikradekdoulik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, let see if CI tests will pass. Thank you!

@jkotas

jkotas commented May 7, 2026

Copy link
Copy Markdown
Member

There are more places where this is hardcoded:

src\mono\browser\browser.proj(219):<EmccStackSize>5MB</EmccStackSize>
src\mono\browser\build\BrowserWasmApp.targets(171):<EmccStackSize Condition="'$(EmccStackSize)' == ''">5MB</EmccStackSize>
src\mono\wasm\build\WasmApp.Common.targets(67):- $(EmccStackSize) - Stack size. Default value: 5MB.

Is this inconsistency intentional?

@pavelsavara

Copy link
Copy Markdown
MemberAuthor

Is this inconsistency intentional?

Yes, that is Mono

@jkotas

Copy link
Copy Markdown
Member

What's the reasoning behind lower limits for CoreCLR? Is there a problem with applying the same lower limits to Mono as well?

@pavelsavara

pavelsavara commented May 8, 2026

Copy link
Copy Markdown
MemberAuthor

What's the reasoning behind lower limits for CoreCLR?

It's "see how low we can set it before things break".

STACK_SIZE is more interesting. We discussed with @davidwrighton that I saw some deep stack traces on the interpreter, but I don't remember where. He said that 2MB should be enough.
And we could possibly weed out some deep interp->native->interp transitions.
The build here is green so, we didn't find the bottom yet.

INITIAL_MEMORY is only about re-allocating the linear memory later, this will not break anything, but possibly make it bit slower to start if this value it too low. I want to see the impact on my macro benchmark. Current value is 128MB which none of the tested/compatible apps need and so currently we are not learning the actual low value from that.

The 32MB is matching Mono default value. I remember you said <20MB should be possible. Do you want to try that ?

Blazor template app uses 84MB large linear memory to start on this branch.

Is there a problem with applying the same lower limits to Mono as well?

STACK_SIZE was changed in #81215 but I don't remember why or what was the previous value.

Mono AOT in particular has big INITIAL_MEMORY footprint growing with size of the code. I think it's about some relocations or trampolines. The initial memory needs to be large enough so that some Mono AOT data segment could be applied by the engine at the initial load. There is dedicated MSBuild logic for calculating it. We may need same thing for R2R later.

Right now Mono is "don't touch it" territory.

@jkotas do you have specific concern or just curiosity ?

@jkotas

Copy link
Copy Markdown
Member

STACK_SIZE is more interesting.

Stack size is user observable. Smaller stack size should be better for perf, but it can break user apps. I think it is ok to change it for CoreCLR. It is a breaking change though. We may want to mention it in the Mono -> CoreCLR breaking change notice that we are going to file eventually.

I remember you said <20MB should be possible

This comment was about the GC heap size specifically. It was not about the total memory consumption.

do you have specific concern or just curiosity?

What is the user observable impact of this change? For example, do you see a smaller working set reported by the OS for a typical wasm app or test? Can this regress startup time for a typical wasm app? (I assume that the growing memory has some time overhead, hopefully it is neglible.)

You will always see me asking questions on perf-related PRs that do not have any numbers in the descriptions ;-)

@pavelsavara

Copy link
Copy Markdown
MemberAuthor

/ba-g known infra issue

@pavelsavara
pavelsavara merged commit 6b1231d into dotnet:mainMay 9, 2026
75 checks passed
@pavelsavara
pavelsavara deleted the INITIAL_MEMORY_STACK_SIZE_ branch May 9, 2026 10:04
@pavelsavara

Copy link
Copy Markdown
MemberAuthor

You will always see me asking questions on perf-related PRs that do not have any numbers in the descriptions ;-)

@jkotas we are getting there. Macrobenchmark can now run measurement on PR/branch.

It will take some time until the code flows thru VMR into preview builds.

imageimageimage

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

arch-wasmWebAssembly architecturearea-Hostos-browserBrowser variant of arch-wasm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[browser][coreCLR] reduce INITIAL_MEMORY and STACK_SIZE

5 participants

@pavelsavara@jkotas@radekdoulik@maraf
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

[browser][coreCLR] reduce initial memory footprint - #127905

Merged
pavelsavara merged 1 commit into
dotnet:mainfrom
pavelsavara:INITIAL_MEMORY_STACK_SIZE_
May 9, 2026
Merged

[browser][coreCLR] reduce initial memory footprint#127905
pavelsavara merged 1 commit into
dotnet:mainfrom
pavelsavara:INITIAL_MEMORY_STACK_SIZE_

Conversation

@pavelsavara

@pavelsavarapavelsavara commented May 7, 2026

Copy link
Copy Markdown
Member

Fixes#127880

@pavelsavarapavelsavara added this to the 11.0.0 milestone May 7, 2026
@pavelsavarapavelsavara self-assigned this May 7, 2026
CopilotAI review requested due to automatic review settings May 7, 2026 08:10
@pavelsavarapavelsavara added arch-wasm WebAssembly architecture area-Host os-browser Browser variant of arch-wasm labels May 7, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to 'arch-wasm': @lewing, @pavelsavara
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reduces the default WebAssembly memory and stack settings used by the CoreCLR browser host, aiming to lower the initial memory footprint during startup (per #127880).

Changes:

  • Decrease Emscripten INITIAL_MEMORY from 128 MB to 32 MB for browserhost.
  • Decrease Emscripten STACK_SIZE from 5 MB to 2 MB for browserhost.
  • Keep the MSBuild CoreCLR WASM relink targets in sync with the browserhost CMake configuration.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

FileDescription
src/native/corehost/browserhost/CMakeLists.txtLowers default INITIAL_MEMORY and STACK_SIZE link options for the browser host to reduce startup footprint.
src/mono/browser/build/BrowserWasmApp.CoreCLR.targetsMirrors the updated memory/stack defaults in the CoreCLR WASM relink pipeline so app relinks match the host configuration.

@pavelsavara
pavelsavara marked this pull request as ready for review May 7, 2026 11:32

@radekdoulikradekdoulik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, let see if CI tests will pass. Thank you!

@jkotas

jkotas commented May 7, 2026

Copy link
Copy Markdown
Member

There are more places where this is hardcoded:

src\mono\browser\browser.proj(219):<EmccStackSize>5MB</EmccStackSize>
src\mono\browser\build\BrowserWasmApp.targets(171):<EmccStackSize Condition="'$(EmccStackSize)' == ''">5MB</EmccStackSize>
src\mono\wasm\build\WasmApp.Common.targets(67):- $(EmccStackSize) - Stack size. Default value: 5MB.

Is this inconsistency intentional?

@pavelsavara

Copy link
Copy Markdown
MemberAuthor

Is this inconsistency intentional?

Yes, that is Mono

@jkotas

Copy link
Copy Markdown
Member

What's the reasoning behind lower limits for CoreCLR? Is there a problem with applying the same lower limits to Mono as well?

@pavelsavara

pavelsavara commented May 8, 2026

Copy link
Copy Markdown
MemberAuthor

What's the reasoning behind lower limits for CoreCLR?

It's "see how low we can set it before things break".

STACK_SIZE is more interesting. We discussed with @davidwrighton that I saw some deep stack traces on the interpreter, but I don't remember where. He said that 2MB should be enough.
And we could possibly weed out some deep interp->native->interp transitions.
The build here is green so, we didn't find the bottom yet.

INITIAL_MEMORY is only about re-allocating the linear memory later, this will not break anything, but possibly make it bit slower to start if this value it too low. I want to see the impact on my macro benchmark. Current value is 128MB which none of the tested/compatible apps need and so currently we are not learning the actual low value from that.

The 32MB is matching Mono default value. I remember you said <20MB should be possible. Do you want to try that ?

Blazor template app uses 84MB large linear memory to start on this branch.

Is there a problem with applying the same lower limits to Mono as well?

STACK_SIZE was changed in #81215 but I don't remember why or what was the previous value.

Mono AOT in particular has big INITIAL_MEMORY footprint growing with size of the code. I think it's about some relocations or trampolines. The initial memory needs to be large enough so that some Mono AOT data segment could be applied by the engine at the initial load. There is dedicated MSBuild logic for calculating it. We may need same thing for R2R later.

Right now Mono is "don't touch it" territory.

@jkotas do you have specific concern or just curiosity ?

@jkotas

Copy link
Copy Markdown
Member

STACK_SIZE is more interesting.

Stack size is user observable. Smaller stack size should be better for perf, but it can break user apps. I think it is ok to change it for CoreCLR. It is a breaking change though. We may want to mention it in the Mono -> CoreCLR breaking change notice that we are going to file eventually.

I remember you said <20MB should be possible

This comment was about the GC heap size specifically. It was not about the total memory consumption.

do you have specific concern or just curiosity?

What is the user observable impact of this change? For example, do you see a smaller working set reported by the OS for a typical wasm app or test? Can this regress startup time for a typical wasm app? (I assume that the growing memory has some time overhead, hopefully it is neglible.)

You will always see me asking questions on perf-related PRs that do not have any numbers in the descriptions ;-)

@pavelsavara

Copy link
Copy Markdown
MemberAuthor

/ba-g known infra issue

@pavelsavara
pavelsavara merged commit 6b1231d into dotnet:mainMay 9, 2026
75 checks passed
@pavelsavara
pavelsavara deleted the INITIAL_MEMORY_STACK_SIZE_ branch May 9, 2026 10:04
@pavelsavara

Copy link
Copy Markdown
MemberAuthor

You will always see me asking questions on perf-related PRs that do not have any numbers in the descriptions ;-)

@jkotas we are getting there. Macrobenchmark can now run measurement on PR/branch.

It will take some time until the code flows thru VMR into preview builds.

imageimageimage

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

arch-wasmWebAssembly architecturearea-Hostos-browserBrowser variant of arch-wasm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[browser][coreCLR] reduce INITIAL_MEMORY and STACK_SIZE

5 participants

@pavelsavara@jkotas@radekdoulik@maraf
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[browser][coreCLR] reduce initial memory footprint - #127905

Merged
pavelsavara merged 1 commit into
dotnet:mainfrom
pavelsavara:INITIAL_MEMORY_STACK_SIZE_
May 9, 2026
Merged

[browser][coreCLR] reduce initial memory footprint#127905
pavelsavara merged 1 commit into
dotnet:mainfrom
pavelsavara:INITIAL_MEMORY_STACK_SIZE_

Conversation

@pavelsavara

@pavelsavarapavelsavara commented May 7, 2026

Copy link
Copy Markdown
Member

Fixes#127880

@pavelsavarapavelsavara added this to the 11.0.0 milestone May 7, 2026
@pavelsavarapavelsavara self-assigned this May 7, 2026
CopilotAI review requested due to automatic review settings May 7, 2026 08:10
@pavelsavarapavelsavara added arch-wasm WebAssembly architecture area-Host os-browser Browser variant of arch-wasm labels May 7, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to 'arch-wasm': @lewing, @pavelsavara
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reduces the default WebAssembly memory and stack settings used by the CoreCLR browser host, aiming to lower the initial memory footprint during startup (per #127880).

Changes:

  • Decrease Emscripten INITIAL_MEMORY from 128 MB to 32 MB for browserhost.
  • Decrease Emscripten STACK_SIZE from 5 MB to 2 MB for browserhost.
  • Keep the MSBuild CoreCLR WASM relink targets in sync with the browserhost CMake configuration.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

FileDescription
src/native/corehost/browserhost/CMakeLists.txtLowers default INITIAL_MEMORY and STACK_SIZE link options for the browser host to reduce startup footprint.
src/mono/browser/build/BrowserWasmApp.CoreCLR.targetsMirrors the updated memory/stack defaults in the CoreCLR WASM relink pipeline so app relinks match the host configuration.

@pavelsavara
pavelsavara marked this pull request as ready for review May 7, 2026 11:32

@radekdoulikradekdoulik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, let see if CI tests will pass. Thank you!

@jkotas

jkotas commented May 7, 2026

Copy link
Copy Markdown
Member

There are more places where this is hardcoded:

src\mono\browser\browser.proj(219):<EmccStackSize>5MB</EmccStackSize>
src\mono\browser\build\BrowserWasmApp.targets(171):<EmccStackSize Condition="'$(EmccStackSize)' == ''">5MB</EmccStackSize>
src\mono\wasm\build\WasmApp.Common.targets(67):- $(EmccStackSize) - Stack size. Default value: 5MB.

Is this inconsistency intentional?

@pavelsavara

Copy link
Copy Markdown
MemberAuthor

Is this inconsistency intentional?

Yes, that is Mono

@jkotas

Copy link
Copy Markdown
Member

What's the reasoning behind lower limits for CoreCLR? Is there a problem with applying the same lower limits to Mono as well?

@pavelsavara

pavelsavara commented May 8, 2026

Copy link
Copy Markdown
MemberAuthor

What's the reasoning behind lower limits for CoreCLR?

It's "see how low we can set it before things break".

STACK_SIZE is more interesting. We discussed with @davidwrighton that I saw some deep stack traces on the interpreter, but I don't remember where. He said that 2MB should be enough.
And we could possibly weed out some deep interp->native->interp transitions.
The build here is green so, we didn't find the bottom yet.

INITIAL_MEMORY is only about re-allocating the linear memory later, this will not break anything, but possibly make it bit slower to start if this value it too low. I want to see the impact on my macro benchmark. Current value is 128MB which none of the tested/compatible apps need and so currently we are not learning the actual low value from that.

The 32MB is matching Mono default value. I remember you said <20MB should be possible. Do you want to try that ?

Blazor template app uses 84MB large linear memory to start on this branch.

Is there a problem with applying the same lower limits to Mono as well?

STACK_SIZE was changed in #81215 but I don't remember why or what was the previous value.

Mono AOT in particular has big INITIAL_MEMORY footprint growing with size of the code. I think it's about some relocations or trampolines. The initial memory needs to be large enough so that some Mono AOT data segment could be applied by the engine at the initial load. There is dedicated MSBuild logic for calculating it. We may need same thing for R2R later.

Right now Mono is "don't touch it" territory.

@jkotas do you have specific concern or just curiosity ?

@jkotas

Copy link
Copy Markdown
Member

STACK_SIZE is more interesting.

Stack size is user observable. Smaller stack size should be better for perf, but it can break user apps. I think it is ok to change it for CoreCLR. It is a breaking change though. We may want to mention it in the Mono -> CoreCLR breaking change notice that we are going to file eventually.

I remember you said <20MB should be possible

This comment was about the GC heap size specifically. It was not about the total memory consumption.

do you have specific concern or just curiosity?

What is the user observable impact of this change? For example, do you see a smaller working set reported by the OS for a typical wasm app or test? Can this regress startup time for a typical wasm app? (I assume that the growing memory has some time overhead, hopefully it is neglible.)

You will always see me asking questions on perf-related PRs that do not have any numbers in the descriptions ;-)

@pavelsavara

Copy link
Copy Markdown
MemberAuthor

/ba-g known infra issue

@pavelsavara
pavelsavara merged commit 6b1231d into dotnet:mainMay 9, 2026
75 checks passed
@pavelsavara
pavelsavara deleted the INITIAL_MEMORY_STACK_SIZE_ branch May 9, 2026 10:04
@pavelsavara

Copy link
Copy Markdown
MemberAuthor

You will always see me asking questions on perf-related PRs that do not have any numbers in the descriptions ;-)

@jkotas we are getting there. Macrobenchmark can now run measurement on PR/branch.

It will take some time until the code flows thru VMR into preview builds.

imageimageimage

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

arch-wasmWebAssembly architecturearea-Hostos-browserBrowser variant of arch-wasm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[browser][coreCLR] reduce INITIAL_MEMORY and STACK_SIZE

5 participants

@pavelsavara@jkotas@radekdoulik@maraf
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[browser][coreCLR] reduce initial memory footprint - #127905

Merged
pavelsavara merged 1 commit into
dotnet:mainfrom
pavelsavara:INITIAL_MEMORY_STACK_SIZE_
May 9, 2026
Merged

[browser][coreCLR] reduce initial memory footprint#127905
pavelsavara merged 1 commit into
dotnet:mainfrom
pavelsavara:INITIAL_MEMORY_STACK_SIZE_

Conversation

@pavelsavara

@pavelsavarapavelsavara commented May 7, 2026

Copy link
Copy Markdown
Member

Fixes#127880

@pavelsavarapavelsavara added this to the 11.0.0 milestone May 7, 2026
@pavelsavarapavelsavara self-assigned this May 7, 2026
CopilotAI review requested due to automatic review settings May 7, 2026 08:10
@pavelsavarapavelsavara added arch-wasm WebAssembly architecture area-Host os-browser Browser variant of arch-wasm labels May 7, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to 'arch-wasm': @lewing, @pavelsavara
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reduces the default WebAssembly memory and stack settings used by the CoreCLR browser host, aiming to lower the initial memory footprint during startup (per #127880).

Changes:

  • Decrease Emscripten INITIAL_MEMORY from 128 MB to 32 MB for browserhost.
  • Decrease Emscripten STACK_SIZE from 5 MB to 2 MB for browserhost.
  • Keep the MSBuild CoreCLR WASM relink targets in sync with the browserhost CMake configuration.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

FileDescription
src/native/corehost/browserhost/CMakeLists.txtLowers default INITIAL_MEMORY and STACK_SIZE link options for the browser host to reduce startup footprint.
src/mono/browser/build/BrowserWasmApp.CoreCLR.targetsMirrors the updated memory/stack defaults in the CoreCLR WASM relink pipeline so app relinks match the host configuration.

@pavelsavara
pavelsavara marked this pull request as ready for review May 7, 2026 11:32

@radekdoulikradekdoulik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, let see if CI tests will pass. Thank you!

@jkotas

jkotas commented May 7, 2026

Copy link
Copy Markdown
Member

There are more places where this is hardcoded:

src\mono\browser\browser.proj(219):<EmccStackSize>5MB</EmccStackSize>
src\mono\browser\build\BrowserWasmApp.targets(171):<EmccStackSize Condition="'$(EmccStackSize)' == ''">5MB</EmccStackSize>
src\mono\wasm\build\WasmApp.Common.targets(67):- $(EmccStackSize) - Stack size. Default value: 5MB.

Is this inconsistency intentional?

@pavelsavara

Copy link
Copy Markdown
MemberAuthor

Is this inconsistency intentional?

Yes, that is Mono

@jkotas

Copy link
Copy Markdown
Member

What's the reasoning behind lower limits for CoreCLR? Is there a problem with applying the same lower limits to Mono as well?

@pavelsavara

pavelsavara commented May 8, 2026

Copy link
Copy Markdown
MemberAuthor

What's the reasoning behind lower limits for CoreCLR?

It's "see how low we can set it before things break".

STACK_SIZE is more interesting. We discussed with @davidwrighton that I saw some deep stack traces on the interpreter, but I don't remember where. He said that 2MB should be enough.
And we could possibly weed out some deep interp->native->interp transitions.
The build here is green so, we didn't find the bottom yet.

INITIAL_MEMORY is only about re-allocating the linear memory later, this will not break anything, but possibly make it bit slower to start if this value it too low. I want to see the impact on my macro benchmark. Current value is 128MB which none of the tested/compatible apps need and so currently we are not learning the actual low value from that.

The 32MB is matching Mono default value. I remember you said <20MB should be possible. Do you want to try that ?

Blazor template app uses 84MB large linear memory to start on this branch.

Is there a problem with applying the same lower limits to Mono as well?

STACK_SIZE was changed in #81215 but I don't remember why or what was the previous value.

Mono AOT in particular has big INITIAL_MEMORY footprint growing with size of the code. I think it's about some relocations or trampolines. The initial memory needs to be large enough so that some Mono AOT data segment could be applied by the engine at the initial load. There is dedicated MSBuild logic for calculating it. We may need same thing for R2R later.

Right now Mono is "don't touch it" territory.

@jkotas do you have specific concern or just curiosity ?

@jkotas

Copy link
Copy Markdown
Member

STACK_SIZE is more interesting.

Stack size is user observable. Smaller stack size should be better for perf, but it can break user apps. I think it is ok to change it for CoreCLR. It is a breaking change though. We may want to mention it in the Mono -> CoreCLR breaking change notice that we are going to file eventually.

I remember you said <20MB should be possible

This comment was about the GC heap size specifically. It was not about the total memory consumption.

do you have specific concern or just curiosity?

What is the user observable impact of this change? For example, do you see a smaller working set reported by the OS for a typical wasm app or test? Can this regress startup time for a typical wasm app? (I assume that the growing memory has some time overhead, hopefully it is neglible.)

You will always see me asking questions on perf-related PRs that do not have any numbers in the descriptions ;-)

@pavelsavara

Copy link
Copy Markdown
MemberAuthor

/ba-g known infra issue

@pavelsavara
pavelsavara merged commit 6b1231d into dotnet:mainMay 9, 2026
75 checks passed
@pavelsavara
pavelsavara deleted the INITIAL_MEMORY_STACK_SIZE_ branch May 9, 2026 10:04
@pavelsavara

Copy link
Copy Markdown
MemberAuthor

You will always see me asking questions on perf-related PRs that do not have any numbers in the descriptions ;-)

@jkotas we are getting there. Macrobenchmark can now run measurement on PR/branch.

It will take some time until the code flows thru VMR into preview builds.

imageimageimage

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

arch-wasmWebAssembly architecturearea-Hostos-browserBrowser variant of arch-wasm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[browser][coreCLR] reduce INITIAL_MEMORY and STACK_SIZE

5 participants

@pavelsavara@jkotas@radekdoulik@maraf
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

[browser][coreCLR] reduce initial memory footprint - #127905

Merged
pavelsavara merged 1 commit into
dotnet:mainfrom
pavelsavara:INITIAL_MEMORY_STACK_SIZE_
May 9, 2026
Merged

[browser][coreCLR] reduce initial memory footprint#127905
pavelsavara merged 1 commit into
dotnet:mainfrom
pavelsavara:INITIAL_MEMORY_STACK_SIZE_

Conversation

@pavelsavara

@pavelsavarapavelsavara commented May 7, 2026

Copy link
Copy Markdown
Member

Fixes#127880

@pavelsavarapavelsavara added this to the 11.0.0 milestone May 7, 2026
@pavelsavarapavelsavara self-assigned this May 7, 2026
CopilotAI review requested due to automatic review settings May 7, 2026 08:10
@pavelsavarapavelsavara added arch-wasm WebAssembly architecture area-Host os-browser Browser variant of arch-wasm labels May 7, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to 'arch-wasm': @lewing, @pavelsavara
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reduces the default WebAssembly memory and stack settings used by the CoreCLR browser host, aiming to lower the initial memory footprint during startup (per #127880).

Changes:

  • Decrease Emscripten INITIAL_MEMORY from 128 MB to 32 MB for browserhost.
  • Decrease Emscripten STACK_SIZE from 5 MB to 2 MB for browserhost.
  • Keep the MSBuild CoreCLR WASM relink targets in sync with the browserhost CMake configuration.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

FileDescription
src/native/corehost/browserhost/CMakeLists.txtLowers default INITIAL_MEMORY and STACK_SIZE link options for the browser host to reduce startup footprint.
src/mono/browser/build/BrowserWasmApp.CoreCLR.targetsMirrors the updated memory/stack defaults in the CoreCLR WASM relink pipeline so app relinks match the host configuration.

@pavelsavara
pavelsavara marked this pull request as ready for review May 7, 2026 11:32

@radekdoulikradekdoulik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, let see if CI tests will pass. Thank you!

@jkotas

jkotas commented May 7, 2026

Copy link
Copy Markdown
Member

There are more places where this is hardcoded:

src\mono\browser\browser.proj(219):<EmccStackSize>5MB</EmccStackSize>
src\mono\browser\build\BrowserWasmApp.targets(171):<EmccStackSize Condition="'$(EmccStackSize)' == ''">5MB</EmccStackSize>
src\mono\wasm\build\WasmApp.Common.targets(67):- $(EmccStackSize) - Stack size. Default value: 5MB.

Is this inconsistency intentional?

@pavelsavara

Copy link
Copy Markdown
MemberAuthor

Is this inconsistency intentional?

Yes, that is Mono

@jkotas

Copy link
Copy Markdown
Member

What's the reasoning behind lower limits for CoreCLR? Is there a problem with applying the same lower limits to Mono as well?

@pavelsavara

pavelsavara commented May 8, 2026

Copy link
Copy Markdown
MemberAuthor

What's the reasoning behind lower limits for CoreCLR?

It's "see how low we can set it before things break".

STACK_SIZE is more interesting. We discussed with @davidwrighton that I saw some deep stack traces on the interpreter, but I don't remember where. He said that 2MB should be enough.
And we could possibly weed out some deep interp->native->interp transitions.
The build here is green so, we didn't find the bottom yet.

INITIAL_MEMORY is only about re-allocating the linear memory later, this will not break anything, but possibly make it bit slower to start if this value it too low. I want to see the impact on my macro benchmark. Current value is 128MB which none of the tested/compatible apps need and so currently we are not learning the actual low value from that.

The 32MB is matching Mono default value. I remember you said <20MB should be possible. Do you want to try that ?

Blazor template app uses 84MB large linear memory to start on this branch.

Is there a problem with applying the same lower limits to Mono as well?

STACK_SIZE was changed in #81215 but I don't remember why or what was the previous value.

Mono AOT in particular has big INITIAL_MEMORY footprint growing with size of the code. I think it's about some relocations or trampolines. The initial memory needs to be large enough so that some Mono AOT data segment could be applied by the engine at the initial load. There is dedicated MSBuild logic for calculating it. We may need same thing for R2R later.

Right now Mono is "don't touch it" territory.

@jkotas do you have specific concern or just curiosity ?

@jkotas

Copy link
Copy Markdown
Member

STACK_SIZE is more interesting.

Stack size is user observable. Smaller stack size should be better for perf, but it can break user apps. I think it is ok to change it for CoreCLR. It is a breaking change though. We may want to mention it in the Mono -> CoreCLR breaking change notice that we are going to file eventually.

I remember you said <20MB should be possible

This comment was about the GC heap size specifically. It was not about the total memory consumption.

do you have specific concern or just curiosity?

What is the user observable impact of this change? For example, do you see a smaller working set reported by the OS for a typical wasm app or test? Can this regress startup time for a typical wasm app? (I assume that the growing memory has some time overhead, hopefully it is neglible.)

You will always see me asking questions on perf-related PRs that do not have any numbers in the descriptions ;-)

@pavelsavara

Copy link
Copy Markdown
MemberAuthor

/ba-g known infra issue

@pavelsavara
pavelsavara merged commit 6b1231d into dotnet:mainMay 9, 2026
75 checks passed
@pavelsavara
pavelsavara deleted the INITIAL_MEMORY_STACK_SIZE_ branch May 9, 2026 10:04
@pavelsavara

Copy link
Copy Markdown
MemberAuthor

You will always see me asking questions on perf-related PRs that do not have any numbers in the descriptions ;-)

@jkotas we are getting there. Macrobenchmark can now run measurement on PR/branch.

It will take some time until the code flows thru VMR into preview builds.

imageimageimage

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

arch-wasmWebAssembly architecturearea-Hostos-browserBrowser variant of arch-wasm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[browser][coreCLR] reduce INITIAL_MEMORY and STACK_SIZE

5 participants

@pavelsavara@jkotas@radekdoulik@maraf