Issue #9634 has been reported by Narihiro Nakamura.

----------------------------------------
Feature #9634: [PATCH]Symbol GC
https://bugs.ruby-lang.org/issues/9634

* 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鐚鈬鱇繧 t閙齷蹶 i銓纈遯 續祟ぢ鐚* 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/