Feature #9634
Updated by authorNari (Narihiro Nakamura) over 10 years ago
I've written a patch to collect most symbols. PATCH: https://github.com/authorNari/ruby/compare/4a91fb7a45f0e3c...symbol_gc.patch https://github.com/authorNari/ruby/compare/13834fb3c...symbol_gc.patch ## Summary * Most symbols in Ruby level are GC-able(generated by #to_sym, #intern, etc..) * Exclude a symbol which is translated ID in C-level from GC-able symbols * Keep Ruby's C extension compatibility * Pass `make test-all` ## Benchmark A benchmark program is here. ``` obj = Object.new 100_000.times do |i| obj.respond_to?("sym#{i}".to_sym) end GC.start puts"symbol : #{Symbol.all_symbols.size}" ``` ``` % time RBENV_VERSION=ruby-r45059 ruby -v /tmp/a.rb ruby 2.2.0dev (2014-02-20 trunk 45059) [x86_64-linux] symbol : 102416 0.24s user 0.01s system 91% cpu 0.272 total % time RBENV_VERSION=symgc ruby -v /tmp/a.rb ruby 2.2.0dev (2014-02-20 trunk 45059) [x86_64-linux] symbol : 2833 0.21s user 0.01s system 90% cpu 0.247 total ``` The total number of symbols is declined. The total time of symgc version is improved because Full GC pressure has been reduced. The result of `make benchmark`. https://gist.github.com/authorNari/9359704 There is no significant slowdown. (I would welcome to try an additional benchmark and report) ## Implementation Detail I classify Dynamic symbol and Static symbol. * Static symbol * Generated by rb_itnern() * A sequential unique number as in the past. * Not GC-able * LSB = 1 * Reserved IDs(147 and below) are exceptional cases * Dynamic symbol * Generated by #to_sym, #intern in Ruby level * RVALUE * GC-able * LSB = 0 * Pin down a dynamic symbol when it translate to ID (e.g. SYM2ID, rb_intern). * Pinned dynamic symbols are never collected. * I'd like to include ID in GC's roots only CRuby internal in order to reduce pinned dynamic symbols. Please read the patch if you want to know more information. ## Acknowledgment The idea of this symbol GC is invented by Sasada Koichi in Heroku,inc. Thank you. -- ja -- RubyレベルのシンボルをGC対象にするパッチを書きました。 https://github.com/authorNari/ruby/compare/4a91fb7a45f0e3c...symbol_gc https://github.com/authorNari/ruby/compare/13834fb3c...symbol_gc ## 概要 * RubyレベルのほとんどのシンボルがGC対象(to_sym,internで作られたもの) * C側でIDに変換された場合はGC対象から除外(rb_intern、SYM2IDなど) * C-APIの互換性維持 * make test-allが通る ## ベンチマーク 以下のプログラムを実行。 ``` obj = Object.new 100_000.times do |i| obj.respond_to?("sym#{i}".to_sym) end GC.start puts"symbol : #{Symbol.all_symbols.size}" ``` ``` % time RBENV_VERSION=symgc ruby -v /tmp/a.rb ruby 2.2.0dev (2014-02-20 trunk 45059) [x86_64-linux] symbol : 2833 0.21s user 0.01s system 90% cpu 0.247 total % time RBENV_VERSION=ruby-r45059 ruby -v /tmp/a.rb ruby 2.2.0dev (2014-02-20 trunk 45059) [x86_64-linux] symbol : 102416 0.24s user 0.01s system 91% cpu 0.272 total ``` 総シンボル数が減少していることがわかる。 シンボル数の現象でFull GCのプレッシャーが削減されたことにより、symgcの速度が向上した。 make benchmarkの結果。 https://gist.github.com/authorNari/9359704 大幅な速度低下は見られない。 (上記以外の追試を歓迎します) ## (ちょっとした)詳細 symbolをstatic symbolとdynamic symbolに分類。 * static symbol * rb_itnernなどで生成されたもの * 従来通り、連番の一意な数値 * GC非対象 * 下位1ビットにフラグとして1を立てる * 147以下の予約済みIDは例外ケース * dynamic symbol * Rubyレベルの#to_sym,#internなどで生成されたもの * RVALUEとして生成 * GC対象 * 下位1ビットは0 * CレベルでID変換(SYM2IDなど)された場合、pindownし、GCで解放されなくなる * Ruby内部でIDはルートに含め、pindownする箇所をなくしたい その他の詳細はパッチを読んでもらえると…。 ## 謝辞 シンボルGCのアイデアはHeroku社のささだこういち様によるものです。 ありがとうございます。 -----