From: "byroot (Jean Boussier) via ruby-core" Date: 2024-05-13T08:47:11+00:00 Subject: [ruby-core:117860] [Ruby master Bug#20485] Simple use of Fiber makes GC leak objects with singleton method Issue #20485 has been updated by byroot (Jean Boussier). Alright, looking at your dump: ```json {"address":"0x7f2b570455b8", "type":"CLASS", "shape_id":2, "slot_size":160, "class":"0x7f2b57045518", "variation_count":0, "superclass":"0x7f2b5707fd30", "name":"Work", "references":["0x7f2b5707fd30", "0x7f2b552d0d98", "0x7f2b704fea00", "0x7f2b552d0b90", "0x7f2b552d0d98", "0x7f2b552d0b68", "0x7f2b552d0b40", "0x7f2b552d0b18", "0x7f2b552d41f0"], "memsize":488, "flags":{"wb_protected":true, "old":true, "uncollectible":true, "marked":true}} ``` This is the `Work` class. ```json {"address":"0x7f2b57045478", "type":"CLASS", "shape_id":2, "slot_size":160, "class":"0x7f2b57045518", "variation_count":0, "superclass ":"0x7f2b570455b8", "real_class_name":"Work", "singleton":true, "references":["0x7f2b552d0bb8", "0x7f2b570455b8", "0x7f2b552d0a50", "0x7f2b704fe910", "0x7f2b552d0a28"], "memsize":384, "flags":{"wb_protected":true, "old":true, "uncollectible":true, "marked":true}} ``` This is the `Work` instance singleton class (`"superclass":"0x7f2b570455b8"`). ```ruby {"address":"0x7f2b552d0bb8", "type":"OBJECT", "shape_id":5, "slot_size":40, "class":"0x7f2b57045478", "embedded":true, "ivars":0, "memsize":40, "flags":{"wb_protected":true}} ``` Is the `Work` instance (`"class":"0x7f2b57045478"`). Using `harb` I can see it's referenced by the `Proc` and the singleton class: ``` harb> print 0x7f2b552d0bb8 0x7f2b552d0bb8: "OBJECT" class: (null) memsize: 40 retained memsize: 40 referenced from: [ 0x7f2b552d0a78 (DATA: proc) 0x7f2b57045478 (CLASS: (null)) ] ``` Which is expected. However following both references, there is no path to the root. So my understanding is simply that one of these references is left on the C stack, and since Ruby's GC is conservative, it cannot know for sure if this is a true reference or not, so it doesn't collect the object. To further prove that this isn't a leak, you could loop in your reproduction script. I suspect the "leaked" objects count will remain at one. ---------------------------------------- Bug #20485: Simple use of Fiber makes GC leak objects with singleton method https://bugs.ruby-lang.org/issues/20485#change-108268 * Author: skhrshin (Shintaro Sakahara) * Status: Open * ruby -v: ruby 3.2.4 (2024-04-23 revision af471c0e01) [x86_64-linux] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- I found a possible memory leak which occurs only when several conditions are met. The code to reproduce the problem is below: ``` class Work def add_method singleton_class.define_method(:f) {} end end 1.times { Fiber.new {}.resume } work = Work.new work.add_method work = nil GC.start num_objs = ObjectSpace.each_object.select { |o| o.is_a?(Work) rescue false }.size unless num_objs.zero? raise "NG" end ``` Expected result: The script exits normally. Actual result: RuntimeError "NG" is raised. If I change `1.times { Fiber.new {}.resume }` to just `Fiber.new {}.resume` or remove `work.add_method`, GC works as expected. Is there any problem at the way to use Fiber in this code, or is it a bug due to Ruby? I tested ruby 3.3.1 (2024-04-23 revision c56cd86388) [x86_64-linux] too and the result was a little different. The code above didn't reproduce the problem, but if I changed `1.times` to `Mutex.new.synchronize`, it was able to reproduce. -- https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/