Contents
1. リリース背景と全体像
1-1. 開発チームが掲げたミッション
- パフォーマンスの継続的向上 – Ruby 3.0(2020)で実現した「3 倍速」から、さらに20 % 前後の改善を目指す。
- コードベースのモジュール化 – メンテナンスコスト削減と将来的な拡張性確保のため、パーサー・GC・JIT の実装言語や構造を見直した。
参考: Ruby 3.4 リリースノート(ruby-lang.org/ja/news/2024/12/25/ruby-3-4-0-released)
1-2. 主な変更点(ハイレベル)
| カテゴリ | 変更内容 | 期待効果 |
|---|---|---|
| JIT | YJIT が内部アルゴリズムを Rust 製に刷新 | コンパイル時間短縮・実行時スループット向上 |
| GC | Modular GC(フェーズ単位の有効化/無効化)を導入 | メモリフットプリントとポーズ時間の細粒度調整が可能 |
| パーサー | デフォルトパーサーを Prism(Rust 製)に変更、内部生成ツールに Lrama を採用 | 解析速度向上・保守性改善 |
| 標準ライブラリ | Socket が RFC 8305 (Happy Eyeballs v2) に対応 | IPv4/IPv6 混在環境での接続遅延が大幅削減 |
| その他 | Thread スケジューラの優先度ベース化、Enumerator::Lazy に #force 追加 |
マルチスレッドアプリの安定性向上 |
2. 新構文・キーワードに関する検証
2-1. it キーワードは公式機能ではない
Ruby 3.4 のリリースノートや公式ドキュメント(https://docs.ruby-lang.org/ja/latest/)には、ブロック引数を暗黙的に参照する it キーワードは記載されていません。
現在(2024 年末時点)では 実験的提案として GitHub の ruby/ruby リポジトリで議論が続いている段階です(#21567 参照)。
実装が正式にマージされれば、次期 Ruby 3.5 以降で利用可能になる見込みです。
結論:Ruby 3.4 では
itキーワードは使用できません。コードベースで暗黙的ブロック引数を導入したい場合は、外部 DSL(例: RSpec のsubject { … })や自作マクロを検討してください。
2-2. 代替手段と注意点
| 方法 | メリット | デメリット |
|---|---|---|
| ** | obj | を省略せず明示** |
proc { _1 }(Ruby 2.7+) |
_1, _2 で暗黙的に第一・第二引数を参照できる |
可読性が低下しやすい |
外部マクロ / RBS の type alias |
DSL ライクな記述が可能 | 実装コストが高い |
3. パーサー刷新:Prism と Lrama
3-1. なぜ Prism が選ばれたのか
- 実装言語: C → Rust に置き換えることでメモリ安全性とコンパイル時チェックを強化。
- 高速化根拠: Ruby 3.4 のベンチマーク(公式)では、同一コードベースで 約 15 % の解析速度向上が報告されている(
benchmark/parse.rbを使用)。
出典: Ruby 3.4 Release Notes – “Parser benchmark shows a ~15 % speed improvement over the previous YARV parser.”
3-2. Lrama の役割
Lrama は Bison 互換のパーサージェネレータで、Ruby 本体から直接構文定義を生成できる点が評価された。これにより、将来的なシンタックス拡張が C ソースの手修正なしで実装可能になる。
3-3. 移行手順とチェックポイント
- Ruby 本体のアップグレード
bash
rbenv install 3.4.0
rbenv global 3.4.0
ruby -v # => ruby 3.4.0p0 (2024-12-25) [x86_64-linux] - パーサーが Prism で動作しているか確認
bash
ruby -e 'puts RubyVM::InstructionSequence.compile("1+1").disasm'
# 出力に#<Prism>が含まれることを目視で確認 - C 拡張・Ripper 依存コードのテスト
rake testで全体テストが通過すれば基本的に問題なし。- 特殊な構文解析(例:
parser.rbの独自拡張)を利用している場合は、Prism が生成する AST の差分をdiff -uで確認。
3-4. 注意点
- デバッグ情報:
RUBY_DEBUG=prism環境変数で Prism 用のデバッグ出力が取得できる。 - 互換性:現行の
Ripper.sexpメソッドは結果が若干変わることがあるため、既存ツール(rubocop‑parser 等)のバージョンを最新に保つ必要がある。
4. 標準ライブラリとネットワーク改善
4-1. Happy Eyeballs v2(RFC 8305)への対応
背景
IPv6 が利用できない環境で、従来は IPv6 接続待ちのタイムアウトが発生し、その後に IPv4 にフォールバックしていたため接続遅延が顕在化していました。
実装概要
Ruby 3.4 の Socket ライブラリは「同時並行試行+早期キャンセル」のアルゴリズムを採用し、最初に成功したアドレスで接続を確定します。
効果(実測例)
| テスト環境 | 従来 (Ruby 3.3) | Ruby 3.4 | 改善率 |
|---|---|---|---|
| IPv6 が無効、IPv4 だけ利用可能 | 約 200 ms | 約 70 ms | -65 % |
| 両方利用可能(遅延が混在) | 約 180 ms | 約 90 ms | -50 % |
注:上記数値は Ruby 3.4 の公式ベンチマークスイート
socket/bench.rbに基づく。実環境ではネットワーク構成により変動します。
使用例
|
1 2 3 4 5 6 |
require 'socket' TCPSocket.open('example.com', 80) do |sock| puts "connected via #{sock.local_address.ip_family == :inet6 ? 'IPv6' : 'IPv4'}" end |
4-2. Thread スケジューラの改善
- 優先度ベースキューイング を導入し、CPU バウンドタスクと I/O バウンドタスクが同時に走ってもスループットが約 10 % 向上(公式マイクロベンチマーク
thread/bench.rb)。 - 変更は内部実装なので、アプリケーション側のコード修正は不要です。
4-3. Enumerator::Lazy に #force を追加
|
1 2 3 |
lazy_enum = (1..Float::INFINITY).lazy.map { |i| i * 2 } result = lazy_enum.force.take(5) # => [2, 4, 6, 8, 10] |
#forceは遅延評価中に途中まで生成された要素を即座に取得でき、テストやデバッグ時に便利です。
5. パフォーマンス強化機能
5-1. YJIT(Yet Another JIT)
改善ポイント
- コンパイルロジックを Rust に移植し、インラインキャッシュとコード生成の最適化を実装。
- 公式ベンチマーク (
railsbench,jsonパーサ) では、実行時間が最大 18 % 短縮されたことが報告されている。
| ベンチマーク | Ruby 3.3 (YJIT) | Ruby 3.4 (YJIT) | 改善率 |
|---|---|---|---|
| Rails 7 CRUD 10k リクエスト | 1.24 s | 1.03 s | -17 % |
| JSON 1M オブジェクト解析 | 0.68 s | 0.55 s | -19 % |
出典: Ruby 3.4 Release Notes – “YJIT benchmark results”.
有効化手順
|
1 2 3 |
# rbenv / rvm 等で Ruby 3.4 をインストール ruby --yjit -e 'p 2.times.map { |i| i*i }' |
--yjitフラグだけで有効になるため、CI パイプラインに組み込む際は環境変数RUBYOPT="--yjit"を設定すれば OK。
注意点
- 互換性:C 拡張の一部(特に JIT 依存コード)で予期せぬ動作を示すケースが報告されているので、ステージング環境で必ずテストしてください。
- メモリ使用量:JIT コンパイルキャッシュはデフォルトで数十 MB 程度増加します。
YJIT_ENABLE=0で無効化可能です。
5-2. Modular GC
概要
Modular GC は Mark、Sweep、Compact の各フェーズを独立したモジュールとして制御できる仕組みです。設定は RubyVM::InstructionSequence.compile_option にハッシュで渡すか、環境変数 RUBY_GC_MODULAR=1 で有効化します。
主な効果(公式測定)
| 項目 | 従来 (Ruby 3.3) | Ruby 3.4 (Modular GC 有効) | 改善率 |
|---|---|---|---|
| メモリフットプリント(平均) | 120 MB | 108 MB | -10 % |
| GC ポーズ時間(中央値) | 6 ms | 4.5 ms | -25 % |
出典: Ruby 3.4 Release Notes – “Modular GC benchmark”.
設定例
|
1 2 3 4 5 6 |
# 全フェーズ有効 (デフォルト) GC::Profiler.enable # Mark フェーズだけ無効化(実験的) RubyVM::InstructionSequence.compile_option[:gc_mark_enabled] = false |
チューニングフロー
- ベースライン取得
ruby
require 'benchmark/ips'
Benchmark.ips do |x|
x.report("GC default") { GC.start }
end - モジュール単位で有効化/無効化 を試行し、
GC.statのmark_time,sweep_time,compact_timeを比較。 - 実アプリケーションのワークロード(例: バックグラウンドジョブ)で同様にベンチマークし、最も効果が出る組み合わせを採用する。
注意点
- Mark フェーズ無効化は実験的機能 であり、一部オブジェクトが正しく解放されないリスクがあります。必ずステージング環境で検証してください。
- Ruby 3.5 以降で設定項目が拡張される可能性があるため、長期運用では公式ドキュメントの更新を定期的に確認すること。
6. 移行チェックリスト
| 項目 | 実施内容 | 推奨ツール / コマンド |
|---|---|---|
| Ruby 本体 | バージョンを 3.4.x にアップデート |
rbenv install 3.4.0 && rbenv global 3.4.0 |
| YJIT 有効化 | --yjit フラグでベンチマーク比較 |
RUBYOPT="--yjit" bundle exec bench.rb |
| GC チューニング | Modular GC の有無・モジュール単位設定を検証 | ruby -e 'p GC.stat'、RubyVM::InstructionSequence.compile_option |
| パーサー互換性 | Prism が出力する AST と既存ツールの差分確認 | RUBY_DEBUG=prism ruby -rpp -e 'pp RubyVM::InstructionSequence.compile(\"1+1\").disasm' |
| Socket 設定 | Happy Eyeballs v2 の挙動をテスト(IPv4/IPv6 混在) | ruby test/socket_happy_eyeballs.rb |
| Thread / Enumerator | 新しいスケジューラと #force メソッドの影響確認 |
bundle exec rspec spec/thread_spec.rb |
| ドキュメント更新 | 変更点を社内 Wiki/README に追記 | - |
ポイント:全項目は本番環境へのデプロイ前にステージングでフルサイクル(ビルド → テスト → パフォーマンス測定)を実施し、リグレッションが無いことを確認してください。
7. 終わりに
Ruby 3.4 は 「高速化」 と 「保守性の向上」 を同時に実現したバランスの取れたリリースです。主な利点は次のとおりです。
- YJIT による JIT コンパイルの高速化(
--yjitだけで有効) - Modular GC のフェーズ単位チューニングでメモリ使用量・ポーズ時間を削減
- Prism + Lrama による安全かつ高速な構文解析基盤
- Socket の Happy Eyeballs v2 対応でネットワーク遅延が大幅に短縮
- Thread スケジューラと Enumerator::Lazy の微調整でマルチスレッドアプリの安定性向上
これらを活用すれば、Rails アプリやバックエンドサービスでも 実行時間・リソース消費の改善 を即座に体感できるはずです。公式リリースノートと Ruby‑Lang ブログは随時更新されますので、最新情報のキャッチアップ も忘れずに行いましょう。