Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not over-commit fiber stacks on Windows #15037

Merged

Conversation

HertzDevil
Copy link
Contributor

Whenever a new fiber is spawned on Windows, currently Crystal allocates a fully committed 8 MB range of virtual memory. This commit charge stays until the stack becomes unused and reaped, even when most of the stack goes unused. Thus it is "only" possible to spawn several thousand fibers concurrently before the system runs out of virtual memory, depending on the total size of RAM and page files:

(0..).each do |i|
  print i, ' '
  spawn { sleep }
  sleep 1.millisecond
end
... 3362 3363 3364 Unhandled exception: VirtualAlloc: The paging file is too small for this operation to complete. (RuntimeError)
  from C:\crystal\src\crystal\system\win32\fiber.cr:24 in 'allocate_stack'
  from usr\test.cr:33 in 'allocate_stack'
  from C:\crystal\src\fiber\stack_pool.cr:45 in 'checkout'
  from C:\crystal\src\fiber.cr:89 in 'initialize'
  from C:\crystal\src\fiber.cr:86 in 'new'
  from C:\crystal\src\concurrent.cr:62 in 'spawn'
  from usr\test.cr:75 in '__crystal_main'
  from C:\crystal\src\crystal\main.cr:118 in 'main_user_code'
  from C:\crystal\src\crystal\main.cr:104 in 'main'
  from C:\crystal\src\crystal\main.cr:130 in 'main'
  from C:\crystal\src\crystal\system\win32\wmain.cr:37 in 'wmain'
  from D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288 in '__scrt_common_main_seh'
  from C:\WINDOWS\System32\KERNEL32.DLL +75133 in 'BaseThreadInitThunk'
  from C:\WINDOWS\SYSTEM32\ntdll.dll +372520 in 'RtlUserThreadStart'

With this PR, for every fresh fiber stack, only the guard pages plus one extra initial page are committed. Spawning 100,000 idle fibers now consumes just around 7.4 GB of virtual memory, instead of 800 GB. Committed pages are also reset after a stack is returned to a pool and before it is retrieved again; this should be reasonably first, as decommitting pages doesn't alter the page contents.

Note that the guard pages reside immediately above the normal committed pages, not at the top of the whole reserved range. This is required for proper stack overflow detection.

@straight-shoota straight-shoota added this to the 1.15.0 milestone Oct 7, 2024
@straight-shoota straight-shoota merged commit f3d49d7 into crystal-lang:master Oct 10, 2024
65 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

2 participants