YouTubeの無限ループでタブが7GB食う、原因はボタン列

YouTubeの無限ループでタブが7GB食う、原因はボタン列
YouTube

YouTubeを開くと、そのタブだけでメモリを7GB食い、CPUコアが張り付いて画面が固まる。世界中のユーザーが先週から同じ症状を訴えている。原因はYouTube側のたった数十行のJavaScriptで、ブラウザはほぼ無実だった。


7GB食うタブと、エンジニアが見つけた無限ループ

YouTubeを再生していると突然タブが重くなり、CPUが100%に張り付き、最悪はブラウザ全体がフリーズする。先週末からr/firefoxを中心にこの報告が急増し、Tom's Hardwareによれば、個別のYouTubeタブだけで 7GB超のRAM を消費するケースまで観測されている。

最初は「Firefoxのアップデートが悪い」と疑われた。だが同じ症状はBraveやMicrosoft Edgeでも起きていて、 ブラウザ依存ではない ことがすぐに分かった。共通点はただ一つ、YouTubeを開いていることだった。

Mozillaのバグトラッカー(Bugzilla)に「YouTube gets in a loop where paints take longer and longer」(描画が次第に遅くなるループにYouTubeが陥る)というチケットが立ったのは3日前のこと。報告したのはMozillaのグラフィックス担当エンジニア、ジェフ・ミュゼラー(Jeff Muizelaar)だ。彼が共有したパフォーマンスプロファイルから、原因は段々と絞り込まれていった。

Multiple people are seeing this in multiple bugs.
(複数のバグで複数の人が同じ症状を見ている)

問題の場所は、動画プレイヤーのすぐ下にある「いいね」「低評価」「共有」などが並ぶ、あの 横長のボタン列 だった。

「ボタンを隠したら広くなった」だけの話

YouTubeのフロントエンドコードには、ytd-menu-renderer というタグがある。これは画面幅に応じてボタンの数を増減させる、いわゆる 「フレキシブルメニュー」 だ。仕組み自体はシンプルで、Mozillaのマルクス・シュタンゲ(Markus Stange)はこう要約している。

  • メニュー要素が前回より広くなったら、ボタンを全部戻す
  • ボタンが収まりきらなければ、1つ消す
YouTubeフレキシブルメニューの自己フィードバックループ
rAFが発火 メニューがはみ出しているか判定 scrollHeight > 上限+8 shrinkFlexibleMenu() ボタンを1つ削除 メニュー要素の幅が逆に広がる (隣接フレックス要素が縮むため) resetFlexibleItems() 全ボタンを戻す 無限 ループ
※ Bugzilla 2035904 のコメントとMozilla開発者の解析に基づく処理フロー。`maybeUpdateFlexibleMenuImpl` の中で再度 `requestAnimationFrame` が呼ばれ、終了条件に到達しないままループが継続する。

普通に考えれば、ボタンを1つ消したぶん幅は狭くなる。次のフレームで再判定しても、もう収まっているはずだから何もしない。これで終わる。

ところが現実は逆だった。ボタンを1つ消すと、 メニュー要素の幅 が逆に広がる。広がったから「お、戻していいな」と判定して全ボタンを戻す。戻すと当然はみ出すから、また1つ消す。消すと広がる。戻す。はみ出す。消す。

requestAnimationFrame (rAF)で毎フレーム呼ばれるこの処理が、終わる条件を満たすことなく回り続ける。シュタンゲが添付したスタックトレースによれば、状況はもっと悪い。

every rAF callback ends up calling requestAnimationFrame twice, so we end up with 2x the number of rAF callbacks on the next tick.
(rAFのコールバックが毎回 requestAnimationFrame を2回呼ぶので、次のティックではコールバック数が倍になる)
rAFコールバック数の倍々増加
※ シュタンゲのコメント「rAFコールバックが毎回 requestAnimationFrame を2回呼ぶので、次のティックではコールバック数が倍になる」に基づき、初期1コールバックから10ティック分の指数増加を表示。実環境ではブラウザのフレームスケジューラとリソース枯渇により、この理論値に達する前に実害が現れる。

倍々で増えていくrAFが、ブラウザのレイアウト再計算を秒間数千回叩き続ける。これが俗にいう 「レイアウトスラッシング」 、または「リフローループ」と呼ばれる状態だ。CPUを焼き、メモリを食い潰し、最終的にタブが応答しなくなる。

なぜボタンを消すと幅が広がるのか。シュタンゲ自身も「自分の環境では再現しない」と書いており、答えは出ていない。Mozillaの別のエンジニア、エミリオ・コボス・アルバレス(Emilio Cobos Álvarez)は「Windowsでよくある分数スケーリングが関係しているのでは」と推測しているが、これも仮説の域を出ない。

興味深いのは、診断にClaudeが使われたこと

このバグレポートには、もう一つ目を引く要素がある。シュタンゲのコメント中、YouTubeの難読化されたJavaScriptを解析した結果として、こう書かれている。

Here's a diagnosis from Claude based on the stacks in the profile and the minified code:
(プロファイルのスタックと最小化されたコードに基づくClaudeの診断は以下)

Mozillaのエンジニアが、最小化されたYouTubeのJSコードとパフォーマンスプロファイルを Claudeに解析させ、その診断結果を公式バグトラッカーにそのまま引用している。返ってきた診断は、難読化された変数名(p.JSC$13973_lastWidth_.D.onStamperFinished など)を追いながら、Polymerのプロパティアクセサが同期的にDOMをレンダリングし直し、その途中で clientWidth を読むことが状態の捕捉ミスを生む、と説明する内容だった。

「AIに難読化コードの解読を任せる」アプローチは、OSSのデバッグ現場で確実に増えている。難読化されたミニファイ済みJSを人間が読むのは消耗の大きい仕事で、その下読みをLLMに任せ、人間は仮説検証に集中する。今回のバグレポートは、その実例を公開ログとして残した一つの記録だ。

賛否はあるだろう。それでも、Mozillaほどの組織のエンジニアが、本番のバグトラッカーで「Claudeの診断によれば」と書く時代に入ったこと自体が、一つの転換点として記憶される。

ブラウザを殺すのはYouTubeのコードという皮肉

このバグの本当に厄介なところは、修正できる立場にいるのが YouTube側だけ だという点にある。

Firefoxでも、Chromium系のBraveやEdgeでも症状が出るということは、requestAnimationFrame 自体の挙動はどのブラウザでも仕様通りに動いている。ブラウザは「何度も再描画してくれ」と頼まれているから素直に再描画しているだけだ。問題は、終わらない仕事を依頼し続けるYouTube側にある。

Bugzilla 2035904 の公式バグレポート概要
項目 内容
バグID 2035904
タイトル YouTube gets in a loop where
paints take longer and longer
プロダクト Web Compatibility
コンポーネント Site Reports
ステータス NEW (未着手)
優先度 P3
深刻度 S4
Webcompat Score 2
影響 site-broken (サイト機能不全)
影響プラットフォーム Windows / Mac /
Linux / Android
報告者 Jeff Muizelaar (Mozilla)
CC追加人数 15人
※ Mozilla Bugzilla の公開バグレポート(Bug 2035904)の各フィールドより取得。Webcompat Scoreはユーザー影響度の指標で、初期値1から3を経て現在2に再評価されている。

バグレポートのKeywords欄には webcompat:needs-diagnosis (ウェブ互換性、診断必要)というラベルが付いていて、Mozillaは「これはFirefoxの内部で直す問題ではない」と扱っている。実際、このバグの解決はYouTube側のフロントエンドエンジニアがフレキシブルメニューの幅判定ロジックを直すまで終わらない。

ユーザー側でできる回避策は、現時点ではいくつかある。ハードウェアアクセラレーションを切ると症状が和らぐという報告がr/firefoxには複数寄せられているし、UIをカスタマイズするブラウザ拡張で ytd-menu-renderer 周辺を非表示にする手もある。ただしどれも対症療法であり、根本原因は依然としてYouTube側にある。

Bugzillaのステータスは「NEW」のまま、優先度はP3。GoogleもYouTubeも、本稿執筆時点で公式声明を出していない。ユーザー数億人を抱えるサービスで、ブラウザを巻き添えにする無限ループが3日経ってもアナウンスされない。この扱いをどう受け止めるかは、見ている人それぞれだろう。

たった数行のコードと、世界中のフリーズしたタブ

バグの正体を整理しておく。問題は 「ボタンを消すと幅が広がる」 というたった一つの観測ミスだ。たぶん、開発時にローカルで動かしていたときには、ボタンを消せば幅が狭くなっていた。ところが本番のYouTubeページの複雑なフレックスレイアウトの中では、ボタンを消すと隣の兄弟要素が縮み、その結果メニュー要素自体が広がってしまう。

この前提のズレを誰も検知できなかったまま、コードはデプロイされた。世界中の何百万というブラウザタブが、現在進行系で同じ無限ループに入り続けている。

レイアウトの自己フィードバックループは、Web開発で古くから知られている罠だ。offsetWidthclientWidth を読みながら同じ要素のスタイルを書き換えると、レイアウトが連鎖的に再計算される。それを requestAnimationFrame の中でやれば、毎フレーム新しい矛盾が生まれる。教科書に載っているレベルの落とし穴に、Googleの巨大なフロントエンドチームが落ちた。

ソフトウェア開発者にとっては、他人事ではない話だと思う。


参照元

他参照

関連記事

この記事を共有する