[ruby-core:125124] [Ruby Bug#21964] Fiber stack acquire can expand unnecessarily.
Issue #21964 has been reported by ioquatix (Samuel Williams). ---------------------------------------- Bug #21964: Fiber stack acquire can expand unnecessarily. https://bugs.ruby-lang.org/issues/21964 * Author: ioquatix (Samuel Williams) * Status: Open * Assignee: ioquatix (Samuel Williams) * Backport: 3.2: REQUIRED, 3.3: REQUIRED, 3.4: REQUIRED, 4.0: REQUIRED ---------------------------------------- In several common scenarios, the fiber stack allocator can choose to expand the fiber stack pool even when there are unreachable (effectively dead) fibers. For example, the following program will eventually crash if GC does not run in time: ```ruby loop do Fiber.new{Fiber.yield}.resume end ``` We have a loop that resumes a fiber, that fiber yields, and then becomes unreachable. Eventually, we will exhaust the OS vm map limit and fail with `FiberError`. However, at most only one fiber (stack) is needed to execute the above program, since the fiber immediately becomes unreachable. To fix this, we run GC before trying to expand the fiber stacks. In practice, fiber stacks are expanded on power of 2, up to 1024 fibers per allocation. So GC is only run in scenarios where we hit this limit. If GC is running normally, or fibers are terminating normally, we may never hit this code path. -- https://bugs.ruby-lang.org/
Issue #21964 has been updated by ioquatix (Samuel Williams). It's worth noting that this is similar to how it's currently handled in `io.c`: https://github.com/ruby/ruby/blob/4eab86efde9c98e8f51caeb95a0cf25acd7958f6/i... ---------------------------------------- Bug #21964: Fiber stack acquire can expand unnecessarily, causing unexpected `FiberError` https://bugs.ruby-lang.org/issues/21964#change-116848 * Author: ioquatix (Samuel Williams) * Status: Open * Assignee: ioquatix (Samuel Williams) * Backport: 3.2: REQUIRED, 3.3: REQUIRED, 3.4: REQUIRED, 4.0: REQUIRED ---------------------------------------- In several common scenarios, the fiber stack allocator can choose to expand the fiber stack pool even when there are unreachable (effectively dead) fibers. For example, the following program will eventually crash if GC does not run in time: ```ruby loop do Fiber.new{Fiber.yield}.resume end ``` We have a loop that resumes a fiber, that fiber yields, and then becomes unreachable. Eventually, we will exhaust the OS vm map limit and fail with `FiberError`. However, at most only one fiber (stack) is needed to execute the above program, since the fiber immediately becomes unreachable. To fix this, we run GC before trying to expand the fiber stacks: https://github.com/ruby/ruby/pull/16535 - this PR also fixes a minor memory leak on the failure path of expanding the fiber pool. In practice, fiber stacks are expanded on power of 2, up to 1024 fibers per allocation. So GC is only run in scenarios where we hit this limit. If GC is running normally, or fibers are terminating normally, we may never hit this code path. -- https://bugs.ruby-lang.org/
participants (1)
-
ioquatix (Samuel Williams)