mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
Allow recycling fibers by GC if not referenced directly
The patch assumes that `struct REnv::cxt` only performs checks with the `OP_BREAK` and `OP_RETURN_BLK` instructions, and does not reference the entity. Therefore, by changing to a weak reference, it is possible to collect fibers that are no longer directly referenced while in the suspended state. However, we need to detach the living env objects that remain in the call stack of the fiber. So, in effect, it involves a revert of following commits. - commita3365d8b3f- commit57ffa1c150Examples of the effects of change are shown below. Note that it was built with `rake MRUBY_CONFIG=host-debug`. ```ruby f = Fiber.new { (x, y, z) = "X", "Y", "Z"; Fiber.yield -> { [x, y, z] } } g = f.resume GC.start p ObjectSpace.memsize_of_all # => 59532 g.call # => ["X", "Y", "Z"] f = nil GC.start ObjectSpace.memsize_of_all # BEFORE => 59532 # AFTER => 58044 g.call # => ["X", "Y", "Z"] ```
This commit is contained in:
@@ -630,9 +630,8 @@ gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
|
||||
{
|
||||
struct REnv *e = (struct REnv*)obj;
|
||||
|
||||
if (MRB_ENV_ONSTACK_P(e) && e->cxt && e->cxt->fib) {
|
||||
mrb_gc_mark(mrb, (struct RBasic*)e->cxt->fib);
|
||||
}
|
||||
// The data stack must always be protected from GC regardless of the MRB_ENV_CLOSE flag.
|
||||
// This is because the data stack is not protected if the fiber is GC'd.
|
||||
mrb_int len = MRB_ENV_LEN(e);
|
||||
for (mrb_int i=0; i<len; i++) {
|
||||
mrb_gc_mark_value(mrb, e->stack[i]);
|
||||
@@ -773,7 +772,20 @@ obj_free(mrb_state *mrb, struct RBasic *obj, mrb_bool end)
|
||||
{
|
||||
struct mrb_context *c = ((struct RFiber*)obj)->cxt;
|
||||
|
||||
if (c != mrb->root_c) {
|
||||
if (c && c != mrb->root_c) {
|
||||
if (!end && c->status != MRB_FIBER_TERMINATED) {
|
||||
mrb_callinfo *ci = c->ci;
|
||||
mrb_callinfo *ce = c->cibase;
|
||||
|
||||
while (ce <= ci) {
|
||||
struct REnv *e = ci->u.env;
|
||||
if (e && !is_dead(&mrb->gc, (struct RBasic*)e) &&
|
||||
e->tt == MRB_TT_ENV && MRB_ENV_ONSTACK_P(e)) {
|
||||
mrb_env_unshare(mrb, e, TRUE);
|
||||
}
|
||||
ci--;
|
||||
}
|
||||
}
|
||||
mrb_free_context(mrb, c);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user