Defender 高 CPU トラブルシューティングとチューニング
このスキルが解決する問題
Windows 開発機では、Microsoft Defender のリアルタイム保護がファイル読み取りのたびにスキャンを実行します。あるプロセスが大量のファイルを読み込むと(IDEA のインデックス、Codex のプロジェクトスキャン、find / による全ディスク走査、Maven の依存関係取得、WSL/Docker 内部 I/O)、Defender は休みなくスキャンを続けることになり、MsMpEng.exe の CPU 使用率が 50% 以上に跳ね上がり、マシン全体が遅延します。
このフローの中核となる洞察は次の通りです:Defender の CPU 高騰のほぼすべての原因は、Defender 自体の故障ではなく、あるファイル I/O の大元が継続的にリアルタイム保護をトリガーしていることです。したがって、トラブルシューティングの鍵は「Defender のパラメータを調整する」ことではなく、トリガー元を特定し、正確な除外設定を適用してスキャン経路から外すことです。これにより、カクつきを解決しつつ、全体的なセキュリティ姿勢は維持します。
トラブルシューティングの流れ
ステップ 0:まず Defender が原因かどうか、そして「どの指標」で CPU を見るかを確認
タスクマネージャーのプロセス CPU 列と、パフォーマンスカウンター \Process(*)\% Processor Time は指標の口径が異なります。カウンターはマルチコアマシンで単一プロセスが 100% を超えることがあります(コアあたり 100% が累積)。タスクマネージャーはそれをコア数で割って表示します。つまり、タスクマネージャーで「61.2%」でも、カウンターでは「766%」(20コアマシン)ということもあります。どちらも正しい値なので、間違った指標で結論を出さないでください。
MsMpEng の現在の実際の使用率(タスクマネージャー基準)を素早く確認:
$cores = $env:NUMBER_OF_PROCESSORS
$c = (Get-Counter '\Process(MsMpEng*)\% Processor Time').CounterSamples | Where-Object { $_.InstanceName -like 'msmpeng*' } | Select-Object -First 1
"MsMpEng: カウンター=$([math]::Round($c.CookedValue,1))% タスクマネージャー換算=$([math]::Round($c.CookedValue/$cores,1))% (マシン $cores コア)"
タスクマネージャーで高く表示されていても、カウンターが継続して 0 の場合は、タスクマネージャーの古い表示値が更新されていないだけです。タスクマネージャーを再起動すれば直ります。Defender を変更する必要はありません。
ステップ 1:トリガー元を特定する(直感ではなく相関関係で)
Defender の CPU 高騰の根本原因は 3 種類あり、特定方法が異なります:
| 根本原因 | 特徴 | 確認方法 |
|---|---|---|
| 外部プロセスによるリアルタイム保護トリガー(最も一般的) | MsMpEng の CPU がパルス状に変動、同時に高い I/O を持つ外部プロセスが存在 | 継続サンプリングし、「MsMpEng が高いときに、どのプロセスの I/O も高いか」を見つける |
| 計画 / バックグラウンドスキャン | CPU が持続的に高く変動が少ない;ScanRunning に値があるか、スケジュールタスクが動作中 | Get-MpComputerStatus で ScanRunning を確認;Get-ScheduledTask -TaskPath '\Microsoft\Windows\Windows Defender\*' |
| Defender 自身のバックグラウンドタスク(定義更新後の検証、クラウドサンプリングなど) | MsMpEng 自身の読み取り I/O が最も高いが、対応する外部の高 I/O プロセスがない | サンプリングし、MsMpEng 自身の I/O が他のプロセスを大きく上回っているか確認 |
主要な診断手段:scripts/diag-mpcpu.ps1 を実行します。数秒間継続サンプリングし、MsMpEng の CPU と各プロセスの IO Data Bytes/sec を同時に記録します。解釈方法:
- あるプロセスの I/O が高いときに MsMpEng も高い → そのプロセスがトリガー元。根本治療のためにステップ 2 へ
- MsMpEng 自身の読み取りが最も高く、外部の高 I/O なし → ステップ 3 へ(バックグラウンドタスク/スキャン)
- MsMpEng が常にほぼ 0 → 問題は Defender 以外にある。別の原因を探る(ユーザーが見ているのはタスクマネージャーの古い値かもしれない)
ステップ 2:根本治療——トリガー元に除外設定を追加
除外設定には 2 種類あり、その違いを理解することが重要です:
- プロセス除外(ExclusionProcess):プロセス名を指定(例:
idea64.exe)。このプロセスがファイルを読み込むときにスキャンをトリガーしなくなりますが、そのファイルが別のプロセスからアクセスされた場合はスキャンされます。正確かつ安全で、優先的に使用します。 - パス除外(ExclusionPath):ディレクトリを指定。そのディレクトリ配下のすべてのファイルに対して、あらゆるプロセス(ブラウザ、EDR 含む)からのアクセスでスキャンされません。キャッシュや仮想ディスクなど、「単なるデータファイルであり、誰がアクセスしてもスキャンする必要がない」シナリオに適しています。プロジェクトのソースコードディレクトリには使用しないでください——プロジェクトのソースコードはプロセス除外で保護すべきです(開発ツールが読むときだけスキャンをスキップし、同じディレクトリにブラウザでダウンロードしたものは引き続きスキャンされます)。これが、
gen-exclusions.ps1のパス導出がキャッシュ/仮想ディスク/ツールのインストールルートのみを出力し、プロジェクトディレクトリを決して自動除外しない理由でもあります。
なぜプロセス除外が優先なのか:パス除外はそのディレクトリ内のすべてのファイルを「すべてのプロセス」に対してリアルタイム保護の対象外にします。プロセス除外は「特定のツール」に対してのみ解除するため、攻撃対象領域がはるかに小さくなります。例えば codex.exe プロセスを除外すれば、Codex がプロジェクトを読むときだけスキャンがスキップされ、同じディレクトリにブラウザでダウンロードしたファイルは引き続きスキャンされます——これが望ましい動作です。
scripts/gen-exclusions.ps1 を実行します。現在実行中の開発系プロセスをスキャンし、既知のツールパターンと照合して、推奨されるプロセス + パス除外を自動生成します。デフォルトは DryRun(プレビュー:提案と理由を表示)。確認後、-Apply を付けて実行すると Defender に書き込みます。このスクリプトは冪等で、実行前に現在の除外設定をバックアップします。
ステップ 3:バックグラウンドスキャン系統の根本原因への対処
計画スキャン / 自動メンテナンスが動作中の場合(ScanRunning に値がある、スケジュールタスクの State=Running)、通常は完了するまで待つのが適切です。強制終了すべきではありません——これは Defender がセキュリティメンテナンスを行っているのです。もし都合の悪い時間に繰り返しトリガーされる場合は、計画を調整します:
# 計画スキャンを確認
Get-ScheduledTask -TaskPath '\Microsoft\Windows\Windows Defender\*'
# クイックスキャン時間を調整(例:毎日午前 3 時)——既存の計画スキャン設定は上書きされることに注意
Set-MpPreference -ScanScheduleQuickScanTime 03:00:00
定義更新後のフル検証(たまに発生)は通常 1 回限りで、完了すれば問題ありません。
ステップ 4:検証
除外設定を追加した後、元の高 I/O 負荷を再トリガーします(IDE のインデックスを再開、find を再実行、Codex にプロジェクトをスキャンさせる)。その後、再度 diag-mpcpu.ps1 を実行します。成功の基準:同じ I/O 負荷のもとで、MsMpEng が以前の高い値からほぼ 0 に低下していること。低下しない場合、除外設定が真のトリガー元をカバーしていません。ステップ 1 に戻り、diag 出力でどのプロセスがまだ同時に高いかを確認します。
セキュリティ境界——絶対に除外しないもの
除外設定は対応するパス/プロセスのリアルタイム保護を低下させます。そのため、境界を設ける必要があります。以下は決して除外に追加してはならないものです(完全かつ権威あるリストは scripts/gen-exclusions.ps1 内の $denyProcs と $denyPathPrefix が唯一の真の情報源であり、ドキュメントのリストは説明用です):
- システムプロセス:
svchost.exe、dllhost.exe、smartscreen.exe、conhost.exe、lsass.exe、csrss.exeなど - ブラウザとその WebView:
msedge.exe、chrome.exe、msedgewebview2.exe—— ブラウザのダウンロードはマルウェアの主要な侵入口です。スキャンを維持します - セキュリティ/管理クライアント:会社が導入した EDR、VPN クライアント(例:深信服 ECAgent、CrowdStrike、SentinelOne)——これらに触れるとコンプライアンス警告が発生する可能性があり、そもそも防御線です
- ユーザーディレクトリ全体 / システムドライブのルート:粒度が粗すぎ、実質的に無防備になります
*.jar、*.exe、*.dll、*.ps1などの実行可能拡張子:実行可能であり、スキャンを維持します。拡張子除外は純粋なコンパイル成果物(*.class)やログ(*.log)など、実行不可能なものにのみ使用します
判断の原則:除外設定は「信頼できる開発ツールがその本来の作業で読み取るファイル」を対象とすべきであり、「CPU 節約のためにすべてを除外する」ためのものではありません。
高度な診断:パフォーマンスレコーダー
diag スクリプトでも正確に特定できない場合、Defender 公式のパフォーマンスレコーダー(管理者権限が必要)を使用します。MsMpEng がどのパス/プロセスに時間を費やしているか、正確なレポートを生成します:
New-MpPerformanceRecord -RecordTo C:\perf.mpdr # 60 秒間収集(その間に高 CPU を再現)
# レポートは最も CPU を消費しているパスとプロセスを指摘し、それに基づいて正確に除外設定を追加
参考ファイル
references/common-exclusions.md—— 一般的な開発ツール(IDE/Java/Node/WSL/Docker/AI コーディングアシスタント/ビルドキャッシュ)の推奨除外カテゴリ一覧。各カテゴリのセキュリティトレードオフに関する説明付き。除外設定生成時にカバレッジを確認するために使用します。scripts/diag-mpcpu.ps1—— 診断サンプリングスクリプトscripts/gen-exclusions.ps1—— 除外設定を自動生成して適用する(デフォルトはプレビューのみ)