From: "mdalessio (Mike Dalessio) via ruby-core" Date: 2026-03-17T22:25:23+00:00 Subject: [ruby-core:125057] [Ruby Bug#21856] Massive performance degradation of `rb_obj_free` for `T_CLASS` since Ruby 4.0 Issue #21856 has been updated by mdalessio (Mike Dalessio). ���� I'm the maintainer of Nokogiri and Loofah. Nokogiri has a "decorator" feature that allows modules to be mixed into node objects dynamically. When a document has decorators registered, Nokogiri calls `node.extend(mod)` on each `Node` object when it is created. This creates a singleton class per `Node` (though not necessarily for every DOM node -- only the ones for which we create a Ruby object). Loofah uses this feature. It defines a `DocumentDecorator` module included in all of its document classes (XML, HTML4, HTML5), which registers `ScrubBehavior::Node` as a decorator for every `Nokogiri::XML::Node`. Loofah traverses the DOM tree and instantiates a Ruby `Node` object for every DOM node. This means every node in every Loofah-parsed document gets a singleton class allocated ��� one per node. Given the fact that Rails uses Loofah to sanitize content, this performance problem is likely to compound badly for Rails applications when sanitizing large HTML pages. ---------------------------------------- Bug #21856: Massive performance degradation of `rb_obj_free` for `T_CLASS` since Ruby 4.0 https://bugs.ruby-lang.org/issues/21856#change-116757 * Author: ahorek (Pavel Rosick��) * Status: Open * ruby -v: ruby 4.1.0dev (2026-01-31T09:41:30Z master 7ef8c470d2) +PRISM [x86_64-linux] * Backport: 3.2: DONTNEED, 3.3: DONTNEED, 3.4: DONTNEED, 4.0: REQUIRED ---------------------------------------- Loofah sanitization is noticeably slower ``` Ruby: 3.4.8 Loofah: 2.25.0 Nokogiri: 1.19.0 Iterations: 100000 user system total real Loofah.fragment + scrub!(:prune) 26.091872 0.000000 26.091872 ( 25.110925) Loofah.scrub_fragment(:prune) 25.913185 0.010392 25.923577 ( 24.948464) Nokogiri HTML parse only 3.852690 0.000000 3.852690 ( 3.705930) Ruby: 4.0.0 & 4.0.1 Loofah: 2.25.0 Nokogiri: 1.19.0 Iterations: 100000 user system total real Loofah.fragment + scrub!(:prune) 38.094207 0.041753 38.135960 ( 36.669463) Loofah.scrub_fragment(:prune) 40.168795 0.000045 40.168840 ( 38.561806) Nokogiri HTML parse only 4.012936 0.052024 4.064960 ( 3.913272) Ruby: 4.1.0 (ruby 4.1.0dev (2026-01-31T09:41:30Z master 7ef8c470d2) +PRISM [x86_64-linux]) Loofah: 2.25.0 Nokogiri: 1.19.0 Iterations: 100000 user system total real Loofah.fragment + scrub!(:prune) 39.004228 0.000000 39.004228 ( 37.694873) Loofah.scrub_fragment(:prune) 39.043199 0.031284 39.074483 ( 37.182785) Nokogiri HTML parse only 3.889100 0.010427 3.899527 ( 3.741622) ``` Originally reported https://www.redmine.org/issues/43737 ---Files-------------------------------- benchmark.rb (1002 Bytes) -- 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/lists/ruby-core.ml.ruby-lang.org/