ブログに戻る
·8分で読める·productdevbook

macOSの通信量モニタを混乱させるヘルパープロセスの正体

ヘルパープロセスは1つのアプリを十数行のネットワーク行に分解してしまいます。macOSでこれが起きる理由と、その先を読み解く方法を解説します。

  • macOS
  • Bandwidth
  • Network monitoring
  • Deep dive

静かな午後にアクティビティモニタを開き、ネットワークバイトでソートし、リストの上部はこう見える: Google Chrome Helper (Renderer)Google Chrome Helper (GPU)Google Chrome HelperSlack HelperSlack Helper (Renderer)Slack Helper (GPU)。「Chrome」や「Slack」の行はありません——ただヘルパーの紙吹雪、それぞれが秒あたり数百キロバイトを引いています。実際にどのアプリが話しているのか? その混乱こそ、Macのヘルパープロセスの通信量帰属がmacOSでネットワークモニターを構築する最も難しい部分である全理由です。

本稿は、なぜアプリがそもそもヘルパーを起動するのか、なぜカーネルがそれらのネットワーク使用量を別個に報告するのか、そしてツールがアプリ別のきれいな数字を出そうとするときの「折りたたみ」が何を意味するかを説明します。

なぜアプリがヘルパープロセスを起動するか

モダンなmacOSアプリはほぼ単一プロセスで動きません。3つの大きな理由があります。

サンドボックス化と権限分離

AppleのApp Sandboxはプロセス単位の境界です。信頼できないHTMLを解析しJavaScriptを実行するレンダラーは、マイクの権限を持つ親とは異なるエンタイトルメントセットで動きます。レンダラーが悪意あるページに侵害されても、爆発半径はそのプロセスで止まります——突然音声を録音したり書類フォルダを読むことはできません。これがChromeとSafariが両方タブやサイトごとに別個のプロセスを出荷する理由、そしてSlack、Discord、Notion(すべてElectronアプリ)が同じパターンに従う理由です。

クラッシュ分離

Chromeの1つのタブがメモリ不足になりJavaScriptエンジンバグに当たっても、ブラウザのすべてのタブをそれと一緒に死なせたくありません。ヘルパープロセスは、1つの悪いページがそのタブに「Aw, Snap」画面を表示し、それ以外には何も起きないことを意味します。同じロジックが、1つのチャンネルを描画するSlackやボイス通話を描画するDiscordに当てはまります。

ElectronとChromiumアーキテクチャ

アプリがElectronで構築されているなら——Slack、Discord、VS Code、Notion、Linear、Figmaデスクトップ、1Password 8、Microsoft Teams、Postman——Chromiumのマルチプロセスモデルを丸ごと継承します。「メイン」プロセス1つ、「GPU」プロセス1つ、「ネットワークサービス」プロセス(しばしばユーティリティと呼ばれる)1つ、ブラウザウィンドウまたは重要なビューごとにレンダラープロセス1つ。レンダラー自身はソケットを開きません。IPC経由でネットワークサービスと話し、ネットワークサービスが実際のTCPハンドシェイクを行います。

その最後の詳細は聞こえる以上に重要です。

なぜMacのヘルパープロセスの通信量帰属が難しいか

macOSカーネルはsocket(2)を呼びそれからconnect(2)/sendto(2)/recvfrom(2)を呼んだPIDにバイトを帰属させます。それはカーネルにとって正しい答え——「Slack」がプロダクトとして何を意味するかを知らないからです。PID 4711が34.117.x.x:443へのソケットを開いたことだけ知っています。

だからnettoplsof -i、生のproc_pidinfo APIに「誰がネットワークバイトを使ったか」と尋ねると、PIDの平らなリストが返ってきます。各PIDにはプロセス名(ディスク上の実行ファイル名)があり、その名前はほぼ常にこんな感じです:

  • Google Chrome Helper
  • Google Chrome Helper (GPU)
  • Google Chrome Helper (Renderer)
  • Google Chrome Helper (Plugin)
  • Slack Helper
  • Slack Helper (Renderer)
  • Slack Helper (GPU)
  • com.docker.backend

素朴なモニター——カーネルのビューを画面にダンプするだけ——はそれを正確に表示します。「この時間にChromeがどれだけ使ったか」に答えるために頭の中で足し合わせる必要のある7つのChrome行が見えます。さらに悪いことに、レンダラーは短命です。タブを閉じるとレンダラーは死にます。新しいタブを開くと、新しいPIDの新しいレンダラーが現れます。1時間にわたって合計すると、答えは数十の死んだPIDに分散しています。それがMacのヘルパープロセスの通信量帰属のコアの課題です: カーネルが公開する単位は人間が考えたい単位と一致しないのです。

「折りたたみ」の意味

折りたたみとは、ヘルパープロセスを——バンドルパス、親PID、または両方で——見て、そのバイトを所属するユーザ可視のアプリに帰属させる行為です。正しくやれば、11のChrome行を見るのを止め、合計付きの「Google Chrome」と呼ばれる1行を見始めます。

いくつかの方法があり、それぞれにトレードオフがあります。

バンドルパスで

すべてのヘルパーは親アプリのバンドル内に住みます。Chromeの場合、パスはこんな感じ:

/Applications/Google Chrome.app/Contents/Frameworks/
  Google Chrome Framework.framework/Versions/.../Helpers/
  Google Chrome Helper.app/Contents/MacOS/Google Chrome Helper

プロセスの実行ファイルパスがツリーのさらに上の別の.appバンドルを含むなら、外側のバンドルがほぼ確実に親です。これはPID変更を生き延びるので、最も信頼できる折りたたみシグナルです——新しいChromeタブを開いても、新しいレンダラーのパスはまだGoogle Chrome.appの下です。

親PIDで

/Applicationsに住むか、バンドル識別子が「実」アプリケーションと一致する親に当たるまでプロセスツリーを上っていけます。動きますが、より脆弱——launchdは孤児プロセスを再親付けし、一部のヘルパーは親ではなくXPCサービスから起動されます。

バンドル識別子のプレフィックスで

SlackのバンドルIDはcom.tinyspeck.slackmacgapです。ヘルパーのバンドルIDはcom.tinyspeck.slackmacgap.helperまたはcom.tinyspeck.slackmacgap.helper.rendererです。インストール済みアプリのテーブルに対するプレフィックスマッチがほとんどのケースを捕まえます。これはAppleが一部のユーザ向けレポートに内部で使う技法です。

実践では、良いモニターは3つのシグナルすべてを使い、1つが欠けたときグレースフルにフォールバックします。

ovaを動かしてみる

一目で分かるメニューバー通信量モニター——ローカル、署名済み、約3MB。

macOS用ダウンロード

Electronの特殊ケース

Electronアプリはそれ自体の段落に値します——とても一般的だから。Slack Helper (Renderer)という名前のElectronヘルパーは実はソケットを開きません——それはネットワークサービスで、Electronバージョンによって通常Slack Helper(接尾辞なし)またはSlack Helper (Plugin)と呼ばれます。レンダラーはChromiumのMojo IPCバス越しにネットワークサービスと話します。

だからむき出しのSlack Helperでしかトラフィックが見えなくても、それはバグではない——それがアーキテクチャです。レンダラーがリクエストを行いますが、カーネルはネットワークサービスがI/Oを行うのを見ます。ユーザの観点から両方が「Slack」の下に折りたたまれるべき。デバッグの観点から、これを知ることはレンダラーが点灯しない理由を考える午後を救います。

Chrome自身にも同じことが当てはまります: 最近のChromeビルドでは、ほぼすべてのネットワークトラフィックがタブごとのレンダラーではなくGoogle Chrome Helper (Plugin)またはネットワークサービスヘルパーから来ます。

単純な合計を信用できない理由

ヘルパーを理解すれば、いくつかの一般的な質問はより答えやすくなります。

「なぜChromeの使用量が低く見えるのか?」 バイトが十数のヘルパーに分散していて、モニターが合計していないから。各個別のヘルパーは控えめに見えます。

「なぜ認識しないプロセスの下に200MBが突然現れたのか?」 動画ストリームのレンダラー、同期(CloudKit、iCloud、Dropbox)を扱うXPCサービス、バックグラウンド作業をするシステムデーモンの可能性が高い。名前だけでなく実行ファイルパスを見ましょう。

「なぜ再起動の間に同じアプリが2つの異なる名前で表示されるのか?」 一部のヘルパーはプロセス名にバージョン番号やUUIDを含みます。ほとんどのモニターはそれらを取り除きますが、すべてではありません。

実践での折りたたみ——そして取り消すとき

ヘルパーを折りたたむモニターはこんなものを表示します:

Google Chrome    412 MB ↓   18 MB ↑
Slack             89 MB ↓    4 MB ↑
Spotify           62 MB ↓  120 KB ↑
Dropbox           34 MB ↓   12 MB ↑

…ではなく:

Google Chrome Helper (Renderer)   38 MB ↓
Google Chrome Helper (GPU)         2 KB ↓
Google Chrome Helper (Plugin)    220 MB ↓
Google Chrome Helper             140 MB ↓
Google Chrome Helper (Renderer)   12 MB ↓
Slack Helper (Renderer)           41 MB ↓
Slack Helper                      48 MB ↓
... (さらに30行続く)

最初のものが実際に欲しいもの。ovaはこの折りたたみを自動で行います——すべてのヘルパーPIDを親バンドルの下にグループ化するので、7つのヘルパー行ではなく「Slack」と読めます。

ヘルパープロセスの折りたたみ
ovaはすべてのヘルパーPIDを親アプリの下にグループ化するので、7つのヘルパー行ではなく「Slack」と読めます。Chrome、Slack、Discord、Telegram、VS Code、Figma——すべて自動的に統合。

実際にヘルパーを見たいとき

折りたたみが邪魔になる1つのケースがあります: 誤動作するアプリのデバッグ。どのChromiumプロセスがソケットをリークしているか、レンダラーがネットワークサービスを迂回しているかを開発者として把握しようとしているなら、生のビューが欲しい。

便利なモニターは折りたたまれた行をクリックして基礎のヘルパーを見せてくれます——ヘルパー別バイト、現在のPID、フル実行ファイルパス。そうすれば既定ビューはきれいで、詳細は1タップ離れたところに。

これはクラッシュ診断にも有用です: 30秒ごとに再起動しTLSセッションを再確立するヘルパーは、意外なバックグラウンドトラフィックを積み上げる可能性があり、それはヘルパーレベルの履歴が見えるときにのみ可視です。

ウォークスルー: 1つのSlackの謎を調査

今日Slackが600MBダウンロードを表示していて、動画を観ていなかったとします。私が確認する順序:

  1. 時間帯のパターンを確認。 午前9時のスパイクはおそらく朝の追いつき同期。平らな24時間カーブはより興味深い。
  2. ヘルパー内訳を確認。 Slack Helper (Plugin)(ネットワークサービス)に90%なら「本物の」アプリトラフィック。レンダラーに奇妙に分散しているなら、リークしたタブが開いているかもしれない。
  3. ワークスペース数を確認。 各Slackワークスペースは永続WebSocketと独自のアバター/ファイルキャッシュを追加。3つのワークスペースは1つのアイドルトラフィックの約3倍。
  4. 画面共有またはハドル履歴を確認。 ハドルはWebRTCを使い、アクティブな間1〜3MB/sを食らう。

これらのいずれにもパケットキャプチャは要りません。ヘルパーを折りたたみ1時間の履歴を保つアプリ別モニターが必要です。

まとめ

ヘルパープロセスは回避すべき癖ではありません——モダンなmacOSアプリが安全で安定して保たれる方法です。代償は「誰がネットワークを使ったか」のカーネルのビューが謎めいた平らなリストのように読めること、そしてそれがMacのヘルパープロセスの通信量集計があらゆる汎用ツールをつまずかせる理由です。macOSのまともな通信量モニターはヘルパー折りたたみをしなければならず、しないものは残りの人生で頭の中で行を合計させます。

現在のツールが生のヘルパー行を表示し「Google Chrome Helper (Renderer)」を1000回目読むのに飽きたなら、ovaをインストールしましょう——メニューバーに約3MBで常駐し、約1Hzでサンプリングし、ヘルパーを自動的に折りたたみます。すべてのデータがMacに留まります。macOS 14以降、Apple SiliconとIntel。