Description

I've written a patch to collect most symbols.

PATCH: https://github.com/authorNari/ruby/compare/4a91fb7a45f0e3c...symbol_gc.patch

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

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.

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

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社のささだこういち様によるものです。

ありがとうございます。