Issue #9633 has been reported by Narihiro Nakamura.
----------------------------------------
Feature #9633: [PATCH]Symbol GC
https://bugs.ruby-lang.org/issues/9633
* Author: Narihiro Nakamura
* Status: Open
* Priority: Normal
* Assignee: Yukihiro Matsumoto
* Category: core
* Target version: current: 2.2.0
----------------------------------------
I've written a patch to collect most symbols.
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/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社のささだこういち様によるものです。
ありがとうございます。
-----
--
http://bugs.ruby-lang.org/