
2026/05/10 5:25
Python 3.14 および 3.15 で導入されたインクリメンタルごみ収集機能の無効化に関する事項
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
Python コアチームは、3.14 および 3.15 のバージョンで実験的に導入されていた増分型ガベージコレクションを、3.13 で採用されていた安定版の世代別モデルに戻した。この決定は、生産環境での過度なメモリ圧力に関する緊急な報告に基づいている。ベンチマークの結果では、世代別コレクションと比較してピークメモリ使用量が最大 5 倍に達することが示されている。増分型 GC はパージ時間を短縮する(例:約 1.3ms)が、現実世界の負荷下での動作の予測不可能さと、正式な PEP レビューが実施されていないことが、スティーリングカウンシルによる無条件での導入非承認へと導いた。
主要な懸念点として、アンチュワン・ピトリュー氏によって指摘されたように、同時に 2 つのコレクターを実行することにより生じる著しい保守上の複雑さがあり、またティム・ペータース氏は、アプリケーション依存のパフォーマンスの驚きにつながるため、パッチリリースへの変更はリスクが高すぎると論じた。ニール・シェメナウア氏のベンチマークは、小規模なパージ時間という利点と、最悪ケースにおける激しいメモリスパイクというトレードオフを浮き彫りにした。収集器を切り替えるためのおすすめオプション(
-X フラグ)が試作されたが、長期的な保守コストの増加を考慮し、デフォルトとして採用されることは拒絶された。
これに対処するため、リバート完了後すぐに 2026 年 6 月にパッチリリース(3.14.5)が発行される予定であり、準備が整っていれば 2026 年 4 月末までに 3.15 の追加版 alpha 9 が出現する可能性がある。
gc.set_threshold() を緩和策として利用しているユーザーは、古いコレクションに戻った際にパフォーマンスの調整を行う必要があることを念頭に置くべきである。増分型 GC は将来リリース(例:3.16+)で再導入される可能性もあるが、標準的な PEP プロセスを通じて現実的なベンチマークによる徹底的な評価が行われるまでは行われられない。本文
Python 3.14 では新しいインクリメンタルガベージコレクション(GC)が標準で搭載されました。しかし、生産環境において重大なメモリ圧力に関する複数の報告があり、私たちはこれを解消するため、3.14 および 3.15 の両バージョンで当該機能を一旦撤回し、3.13 で採用されていたジェネレーショナル GC に回帰することを決定しました。
3.15 は現在アルファ段階にあるため、このような変更は問題ありません。一方、3.14 がパッチリリースである以上、不測の事態とは言えますが、旧型の GC は既に実証済みであり、新型のインクリメンタル GC は PEP(Python 提案)の手続きを経ずに導入され、かつ 3.13 の最終リリース直前に撤回されていました。これはコアチームおよび steering council とでも協議の上で確認済みです。
もし 3.16 でインクリメンタル GC を再導入したい場合は、通常の PEP プロセスを通じ、さらに徹底的な評価を経て実装すべきでしょう。
スケジュール:
- 3.15: 最初のベータ版は現在からわずかに不足する週(2026 年 5 月 5 日)に予定されています。もし撤回パッチを来週のうちに完了できるようであれば、追加のアルファ版 9 をorelease することを目指します。
- 3.14: 次にリリースされるべきパッチバージョン 3.14.5 は当初 2026 年 6 月 9 日を予定していましたが、撤回準備が完了次第、その時期よりも早くリリースいたします。
これらの日程が確定次第、このトピックおよびリリース PEP を更新いたします。
pitrou (Antoine Pitrou)
2026 年 4 月 17 日 7:37
スタートアップ時にどちらの GC を選択できるようにするオプションを両方含めることは可能でしょうか。それとも、メンテナンスコストという点でやりすぎでしょうか?
hugovk (Hugo van Kemenade)
2026 年 4 月 17 日 8:37
メンテナンスコストが高すぎます。3.14 では 2 つの GC を導入する一方で、3.13 および 3.15 ではわずか 1 つにするという状況は、メンテナンスをより困難にしますし、リスクも大幅に高まります。これは将来の PEP において評価すべきレベルの問題です。
tim.one (Tim Peters)
2026 年 4 月 17 日 9:22
私が CPython の gc モジュールを直接担当していたのは長い以前の話ですが、現状の議論は理にかなっているように思われます。これはデリケートなコードであり、「器用な手抜き」と呼ばれるテクニックを使うことで、gc オブジェクトのプロトコルヘッダ構造体を 3 メンバから 2 メンバに削減した際、その後の可読性が著しく低下しました(注:文脈上「pre-header struct」の記述)。このコードをいかにシンプルに保つかは、すべての人にとって望ましいことです。
特にフリースレッド化の世界では、レース条件によるメモリ破損が、gc がついに全てのコンテナオブジェクトを処理する瞬間に初めて表面化することがあります。これは GIL がある場合でも、欠陥のある拡張モジュールによって引き起こされるメモリ破損が見られた典型的なケースです。
storchaka (Serhiy Storchaka)
2026 年 4 月 17 日 11:18
しかし、3.14 および 3.15 の両方に 2 つの GC を備えてもよいかもしれません。旧型 GC をデフォルトとしつつ、新型 GC は実験的なオプションとして提供できるようにするでしょう。ただし、これによってコードが著しく複雑化しない限りです。
pitrou (Antoine Pitrou)
2026 年 4 月 17 日 12:26
私も同様の考えです。@nas と私は互いに-X フラグを使って GC バージョンを切り替えるブランチを作成しました。実現は可能ですが、両方のバージョンを維持することは長期的なメンテナンス負荷を増大させます。 その点では、+1 は与えますが、3.16 以降に 2 つのバージョンを併存させることについては賛成です(注:原文の文脈より、「旧型 GC をデフォルトにしつつ新規機能を追加する」方向への賛同と解釈)。
nas (Neil Schemenauer)
2026 年 4 月 17 日 16:19
私のプロトタイプにおいて、スタートアップ時に選択できるようにしたところ、インクリメンタル GC はコード約 1,600 行を追加しました。コードが十分に分離されているため、メンテナンス面ではそれほど悪くありません。gc_inc.c と gc_gen.c を独立したコンパイルユニットとして保持しておいても、測定可能な性能劣化は見られませんでした。 ただ、より多くのコードと複雑さを伴うため、慎重かつ安全な選択としては旧型のものに戻ることを推奨します。
新たな GC を導入しようとした経験から考えると、理想的には 3.16 のリリースなどにおいて、新規機能をオプトイン(ユーザー側で有効化)とし、デフォルトは旧型を維持する仕組みが望ましいでしょう。Java ではこれを実践しています。一方、Java には新 GC を研究している専門チームがありますが、我々はいくつかのメンバーが余暇に手を動かしているだけという実情です。ちなみに、すでに 2 つの GC 実装があります(フリースレッド対応版はほぼ独立した別物です)。
昨夜追加のタイミングベンチマークを行いました。その結果、インクリメンタル GC は最大 GC パウズ時間が短いことが確認できました。もしこれが気になる場合は、そちらを好むかもしれません。一方で課題として、特に循環型 garbage が大量に生成されるケースでは、プロセス全体のメモリ使用量が劇的に増加する可能性があります(私が確認した最悪のケースは 5 倍でした)か、ランタイムが slows です(GC で消費される時間が長くなり、総実行時間が増加します)。あるテストランでは、インクリメンタル GC では最大 пауズ 1.3ms ですが、ジェネレーショナル GC では 26ms と大幅に差が出ました。ただしピーク時の RSS サイズはインクリメンタル GC の場合で 2.7 倍増でした。
なお、Sergey(注:先頭にある Sergey Storchaka 氏ら)から旧 GC に回帰するための PR を作成する申し出がありました。私がレビュー担当になりますが、互いにプロトタイプを既に持っているので、すぐに済むのではないかと予想します。
pitrou (Antoine Pitrou)
2026 年 4 月 17 日 17:08
補足ですが、その結果は現実世界のワークロードにおけるものでしょうか、それとも大量のサイクルを生成するように設計されたシンセティックなマイクロベンチマークのものでしょうか?
nas (Neil Schemenauer)
2026 年 4 月 17 日 18:37
リアルワールドではなく、完全に合成データで生成したものです。大量のサイクルを生成しただけです。より現実的な環境でのベンチマークや、実際のアプリケーションでテストを行った人からのレポートがあれば素晴らしいと思います。
pyperformance スイートには、循環型 GC を現実に近い形で行使するような興味深いベンチマークはほとんど含まれていません(ベンチマークプログラムはメモリを使わないか、長時間走らないか、リファレンスサイクルを生成しないため)。「gc_collect」や「gc_traverse」という項目もありますが、これらはマイクロベンチマークであり、現実的ではありません。先日追加した新しいものも、サイクルを作成していません。これは大きなオブジェクトグラフを作成しながらの GC オーバーヘッドをテストするために意図されています。もしこれを基準としてチューニングすると、「GC を実行させるな」結論に達してしまうでしょう(サイクルがないためオーバーヘッドだけが残ります)。
最近最も興味深いケースは Sphinx の遅延問題でした。それは以下の 2 つの特徴を持っていました:コンテナオブジェクトを多数作成すること、およびそれらの中の一部にリファレンスサイクルが含まれていること。その遅延は解決されました。
現実に即したベンチマークやリアルなレポートがない現状では、大規模な合成ベンチマークセットを導入することが有益だと考えます。少なくとも、これらのベンチマークがカバーする範囲の状況下で、循環型 GC の性能が過度に劣化していないことを確認できるでしょう。
hugovk (Hugo van Kemenade)
2026 年 4 月 17 日 19:35
これが 3.13 で撤回を引き起こした問題です。そのバグ報告が開かれた数日後に撤回が実施されました。
tim.one (Tim Peters)
2026 年 4 月 17 日 20:12
あらゆる場面で永遠に続いているように見える問題です。楽観的ではありません。以前別のトピックで言いましたが、私たちが望める最高の結果は、「現実世界の病理現象(不具合)が時々発生するにつれて、それに気づいて回避する新たなヒューリスティクスに偶然ぶつかること」くらいでしょう。歴史的に見て、私が sorting や pymalloc で対処してきたようなケースのほとんどは、初めから Stack Overflow に上がっていました。「説明不能な低速化」という問題に対して「ランダム」なユーザーが助けを求めていました。
私が Python の現在の sort アルゴリズムを書いていた頃、様々なプラットフォームにおけるタイミング結果に関するレポートは、「sortperf.py」(当時は標準配布に含まれていた簡潔な合成ベンチマークプログラム)を実行した人々からしか得られませんでした。リアルなアプリケーションでリアルなデータを走らせた結果は 1 グループしかなかったので、彼らは「2 倍高速になった!」という結果を共有できましたが、社内のデータには触れることができませんでした。
ごく最近に sort アルゴリズムの変更案について発表しましたが、ユーザーからタイミング結果のみの報告(データ不要)を懇願しました。その際に入ってきた返信はたった一通でしたが、心より感謝申し上げます。辞書の衝突解決戦略の一連の評価でも同様のストーリーです。圧倒的に合成入力に基づいて判断されており、現在の戦略を除くほぼ全てが、リアルなアプリケーションからの希少な報告による悲惨な挙動のために最終的に放棄されました。ただしその場合、「致命的」なキーの集合が存在することは証明可能です。「疑問は、現実世界のデータがその状態に偶然遭遇する確率はどれくらいか」というより繊細な点にあります。
これは Python 特有の問題ではありません。powerful な「powersort」マージ順序ヒューリスティクスを共同考案した学者である Sebastian Wild は、「現実世界のデータ」への絶え間ない呼びかけに対する極めて不良な反応を報告しています。主に彼が作成する造作された悪ケース(contrived bad cases)に引き寄せられる傾向があります。
一方、私は最初からメインブランチ上の見かけ上 2 次元の動作について課題を開いた記憶があります。その当時は GC の変更が原因であることを全く知らず、whittled テストケースを作成しましたが、これによりほとんどサイクルは生成されませんでした。これは単に当時実装されていたヒューリスティクスを、過度に頻繁に実行するよう強引に誘発するだけであり、理に適っていませんでした。
sorting の多くは比較的可予測な最悪ケースの O() 動作を持っていますが、GC の文脈はそれよりもはるかに複雑で混乱しています!これが事実です。疑いようがありません。「平均的な」動作を予測する用途としては殆ど役立ちませんが(そもそも「典型的なアプリ」という概念自体が存在しないため)、リアルライフで見られる可能性の限界を具体化するには実用的な助けになります。
この事実は、パッチリリースでもインクリメンタル GC を容易に試せるようにする正当な理由となっています。そうでなければ、現実世界のフィードバックを得る機会(かつては「希薄だが壊滅的なケース限定」から)が「本質的には皆無」へと縮小してしまいます。もっている手札をどう使うかです。
gpshead (Gregory P. Smith)
2026 年 4 月 17 日 20:49
プロセス上、パッチリリースでこのような大規模な変更であることは明らかですが、それでもパッチリリース向けにリリースカンディデート(RC)を出すことで、安定化宣言前に広範なテストを可能にする余地はありませんか。例えば 3.14.5rc1 などが考えられますか?
tim.one (Tim Peters)
2026 年 4 月 17 日 23:12
私の意見では、インクリメンタル GC を無条件に採用することは、パッチリリースにとってリスクが過大です。そうしたリリースにおける基本原則は「まず害をなすことなかれ」です。変更の規模自体よりも以下の点が重要です:
- これは実装の根本的な部分に関わる変更であり、すべてのプログラムに影響を与えます(循環を作成しないプログラムでも)。
- コードの一部は微妙でデリケートです。
- アプリに依存したパフォーマンスの「サプライズ(予期せぬ挙動)」を生み出す長年の歴史があります。
この変更のプレリリース期の経過にも例外はありませんが、現時点まで発見されている全てのサプライズはコア開発者によって発覚しています(「Sphinx 報告」についても @AlexWaygood の勇猛なデバッグ活動の結果です)。Neil の合成テストにより、はるかに悲惨なサプライズが発生する可能性があることは疑いようがありません。
したがって、「リスクが過大」と判断します。
@nas は、インクリメンタル GC を有効にするスタートアップオプションを実装することは、適度な労力で可能だと考えているようです。もしそうなら、私は以下に同意します:
- 幸運があれば、デフォルトでは可視化された変更はありません。
- 意欲的なユーザーが最小の負担で現実世界の「両方向(比較)」の結果を得る手段を提供することになり、潜在的に私たちが得られる現実世界データの量は大幅に増加する可能性があります。実際にそれが起こるとは限りませんが。
私が Python の現在の list.sort() を書く際、開発テストのためにパッチを追加し、リストへの新しいメソッドとして提供しました。「前」と「後」を比較するには、Python の実装コードで 1 つの文字だけを変更するだけでよかったです。これは有効であり、私のテスト生活を大幅に楽にしました。スタートアップオプションは、GC の比較調査においても同様に生活をしやすくできるでしょう。
tim.one (Tim Peters)
2026 年 4 月 18 日 4:58
この項にはメリット(最大 GC パウズ時間の削減)しか挙げられていないが、デメリットは一切記載されていない点が気になります:
- 私はニュースファイルから情報を得たいので、「楽観的セールスピーチ」は求めていません。
- 私自身のアプリの多くでは、 pauses 時間には興味を持ちません。いくつかのアプリは完了までに数日かかりますが、たとえ 5% 長くても私には意味があります:待機時間が 3〜4 時間増えることになります。これらは通常研究目的であり、次の試みの方向性を示す結果が必要です。ただし、私は通常、サイクル(あるかないかを問わず)を十分に作成しないことがわかっているフェーズでは GC を何時間も無効化しています。
- 私のように考えるべきというつもりはありませんし、GC パウズ時間の削減が他の人のアプリにとって非常に重要であることも充分理解しています。しかしながら、トレードオフについてはオープンにすること、さらには変更前に広く議論することは重要です。PEP プロセスはこれらを扱い得ますが、内実装の変更においてそのような「重いプロセス」を適用するのはどうも適切ではありません。
- また、殆どの実装変更が重大な潜在的不利益を伴わないことも事実です。
したがって、私の側から簡単には答えられませんが、今後「完全開示」においてより良い結果を出せることを願っています。
hugovk (Hugo van Kemenade)
2026 年 4 月 18 日 17:36
うーん、我々はこれをしていませんね。最後の RC 以降に RC を出さないという仮定を立ててしまいました。サーバーへのアップロードは停止したものの、デモビルドくらいはうまくいったようです。macOS や Windows のビルドも試していませんでした。とりあえず実行して必要に応じて修正するアプローチになるでしょう。
hugovk (Hugo van Kemenade)
2026 年 4 月 18 日 17:45
少し細かい指摘ですが、Sphinx 報告は以前の貢献者によって既に発見されており、根本原因を特定したのは Bellevue スプリント期間中であることを付け加えます。同じ部屋に多くの人がいてくれたことは確かに助かりました!(Meta さん、ありがとう!)
tim.one (Tim Peters)
2026 年 4 月 18 日 19:03
そのようなご説明があり、ありがとうございます。 まだ扱われていない問題があります:人々はすでに 3.14 に耐えている状態です。「まず害をなすことなかれ」がパッチリリースの絶対原則である私の信念からすれば、インクリメンタル GC の撤回も彼らに害をもたらす可能性があります。特に、GC.set_threshold() の値を選択して自身のアプリで良好な動作を実現し、(実際にはインクリメンタル GC に切り替わったことで害を受けていたアプリに対して有効な緩和策となっていました)という多大な労力を費やした人々は、ジェネレーショナル収集機に戻った際にその努力が裏目に出るかもしれません。
私が知る限りではありませんが、私の印象では、その道を辿った人のほとんどは threshold0 を減らして Gen1 の収集を頻繁に行う(つまり長期間生きるサイクルを早期に回収する)方向に進めたようです。これは古い 3 ジェネレーション収集機に対して誤った対応です:彼らは Gen2 の収集のたびに全てのサイクルを回収します(一方、インクリメンタル GC は Gen1 の試行ごとにその一部しか回収しないため、「同等の効果を得るためには」インクリメンタル GC の場合は Gen1 収集をより頻繁に行う必要があります)。
この視点からすると、全体として最も害が少ないのは、インクリメンタル GC をデフォルトのまま(既に存在しているもの)にしつつ、スタートアップオプションで旧型の 3 ジェネレーション収集機への切り替えを追加することかもしれません。(インクリメンタル GC が依然として一部のアプリで不快なサプライズをもたらしていることを認めての事です)。 残念ながら、純粋な勝利は得られないでしょう。
nas (Neil Schemenauer)
2026 年 4 月 19 日 1:47
これを作成しました。眼球に鋭い棒を突くよりはマシではないでしょうか。3.14t の GC で既に非常に深刻な問題を見つけた上に、その修復に取り組んでいます。
nas (Neil Schemenauer)
2026 年 4 月 19 日 1:51
そのツールによる結果:3.13 vs 3.14 レジェンド(ベースと比較、サイクル/extra/live で整合させたもの):
- t(s) : 新しいビルドの総時間
- t% : ベースに対する時間変化率% ((new-base)/base*100)
- rss : 新しいビルドのピーク RSS メモリ使用量
- rss% : ベースに対するピーク RSS の変化率%
- trash: 新しいビルドでの最大未回収循環型ガベージ
- trash%: ベースに対する最大-trash の変化率%
- pause: 新しいビルドでの最大 GC パウズ時間(ms)
- pause%: ベースに対する最大 GC パウズ時間の変化率%
- peaked : 新しいビルドの RSS と trash が最終 25% の実行の前にピークに達した場合「yes」
私の修正を適用した後の 3.14t の結果:RSS の延期バグが修復され、