磁碟清理 - Windows Disk Cleanup 實戰範例
「C 槽剩 2 GB,VS Code 連開檔都警告磁碟滿,又不敢亂刪。」這是 Windows 開發者最常見的噩夢。直接動手刪是最大的反模式 — 不先量測就憑直覺刪 C:\Windows\Temp、跑內建的「磁碟清理」就期待沒事。
本範例示範如何把 Superpowers 的除錯與驗證 skills,從開發場景轉移到系統運維場景:用 Systematic Debugging 找出真正占空間的元兇,而不是亂槍打鳥;用 Verification 在每個刪除步驟前後確認系統運作正常。
⚠️ 本範例的最高原則:任何刪除動作都先 dry-run 列出 → 使用者確認 → 才執行。不破壞系統運作是紅線,不是 nice-to-have。
專案概述
情境:Windows 11 開發機,512 GB SSD,C 槽 $env:SystemDrive 只剩 1.8 GB。症狀:
- Visual Studio 2022 編譯時跳出「磁碟空間不足」
- Docker Desktop 無法啟動 container
- Windows Update 失敗(
0x80070070) - Hibernation 與 Pagefile 都在 C 槽
目標:
- 釋出至少 30 GB(讓 C 槽回到 > 10% free)
- 絕不影響系統運作(不藍幕、不丟資料、不誤刪登錄/系統檔)
- 每個刪除動作都可逆(先進回收桶或可重建)
技術棧:Windows 11 + PowerShell 7 + WizTree(可視化掃描)+ VS 2022 + Node.js + Docker Desktop
核心挑戰:
- Windows 內建「磁碟清理」預設只清很淺的東西,Deep clean 需要管理者 + DISM
- 開發機的「肥肉」散落:N 個
node_modules、N 個.vsbuild cache、Docker images、WinSxS 備份 - 系統檔(
C:\Windows\*)90% 不能動,動了就藍幕 - 沒有「明顯大檔」,而是「千個小檔累積」
完整開發流程
第 1 步:Systematic Debugging — 先量測,不要猜
鐵律:不做根因調查,不許提刪除方案。看到「C 槽滿」直覺去清 Temp 就是猜測式修復。
階段 1:穩定「重現」+ 量化基線
# T0 基線:目前可用空間
Get-PSDrive C | Select-Object Used, Free, @{n='Total';e={$_.Used + $_.Free}}
# Used: 483.2 GB
# Free: 1.8 GB ← 紅線區
# Total: 485.0 GB
基線寫下來:1.8 GB 釋放前。任何清理動作都要對照這個數字(否則分不清是「這次清的生效」還是「剛才重開機釋放的」)。
階段 2:多層證據收集 — 找出真正的肥肉
C 槽是個多層結構,先確定肥肉在哪一層,別每一層都掃:
# Level 1: C:\ 根目錄下誰最肥
Get-ChildItem C:\ -Directory -Force -ErrorAction SilentlyContinue |
ForEach-Object {
$size = (Get-ChildItem $_.FullName -Recurse -Force -File -ErrorAction SilentlyContinue |
Measure-Object Length -Sum).Sum
[PSCustomObject]@{
Dir = $_.Name
GB = [math]::Round($size / 1GB, 2)
}
} | Sort-Object GB -Descending | Select-Object -First 10
# 預期輸出(範例):
# Windows 41.2 GB
# Users 38.5 GB ← 通常這裡 (開發機)
# ProgramData 19.3 GB
# Program Files 15.8 GB
# $WinREAgent 4.2 GB ← 修復代理
# Program Files (x86) 3.1 GB
# ...
斷點:多數情況 C:\Users\<你>\ 最肥。深入該層:
# Level 2: C:\Users\<你>\ 下誰最肥
Get-ChildItem "$env:USERPROFILE" -Directory -Force -ErrorAction SilentlyContinue |
ForEach-Object {
$size = (Get-ChildItem $_.FullName -Recurse -Force -File -ErrorAction SilentlyContinue |
Measure-Object Length -Sum).Sum
[PSCustomObject]@{ Dir = $_.Name; GB = [math]::Round($size / 1GB, 2) }
} | Sort-Object GB -Descending | Select-Object -First 8
# 範例輸出:
# AppData 28.1 GB ← 開發機這裡最肥
# Documents 5.6 GB
# .nuget 3.2 GB ← NuGet cache
# Downloads 2.8 GB
# source 2.1 GB ← 程式碼
# .dotnet 1.4 GB
AppData 28 GB 是大肥肉。再深入:
# Level 3: AppData 三大子目錄(Local/Roaming/LocalLow),通常 Local 最肥
Get-ChildItem "$env:LOCALAPPDATA" -Directory -Force -ErrorAction SilentlyContinue |
ForEach-Object {
$size = (Get-ChildItem $_.FullName -Recurse -Force -File -ErrorAction SilentlyContinue |
Measure-Object Length -Sum).Sum
[PSCustomObject]@{ Dir = $_.Name; GB = [math]::Round($size / 1GB, 2) }
} | Sort-Object GB -Descending | Select-Object -First 10
# 範例輸出:
# Temp 6.2 GB ← 可清
# Microsoft\VisualStudio 5.1 GB ← 含 ComponentModelCache (可清)
# Docker 4.3 GB ← Docker WSL images
# npm-cache 2.1 GB ← 可清 (pnpm/npm cache)
# pip 1.8 GB ← 可清
# Packages 1.5 GB ← UWP apps,不要動
根因:不是「Temp 太肥」,而是「多個獨立的快取各自 1-6 GB,累積成 28 GB」。沒有任何單一殺手級大檔,因此需要結構化清理計畫,不能只清一個地方。
💡 可選:用 WizTree 視覺化掃描(比 TreeSize 快 100x,因為直接讀 MFT)。掃整個 C:\ 約 5 秒,GUI 上一目了然哪個資料夾肥。本範例用 PowerShell 示範掃描,實務建議兩者並用。
第 2 步:Writing Plans — 分類清理計畫
觸發:
使用 writing-plans skill 把發現的肥肉分成可清 / 謹慎清 / 不可動 三類,逐層驗收
計畫(分四層風險等級):
階段 A — 安全清理(系統內建工具,低風險,~10 GB)
- [ ] 內建 cleanmgr /sageset+sagerun(含 Windows Update 殘留、Delivery Optimization)
- [ ] DISM /Online /Cleanup-Image /StartComponentCleanup(WinSxS 壓縮)
- [ ] 清空資源回收桶
- [ ] 清 Windows 事件記錄 wevtutil
- [ ] 驗收:C 槽 free > 11 GB,系統可重開、可開 VS
階段 B — 開發機 dev cache(中風險,完全可重建,~15 GB)
- [ ] Node: npm/pnpm cache clean --force(.npm、.pnpm-store)
- [ ] .NET: dotnet nuget locals all --clear、clean bin/obj
- [ ] pip cache purge
- [ ] VS 2022: ComponentModelCache、BackupFiles
- [ ] Docker: docker system prune -a(先確認沒在用)
- [ ] 驗收:重 build 一個專案、docker pull hello-world 跑通
階段 C — 謹慎清理(需 dry-run + 確認,~8 GB)
- [ ] Downloads:列出 > 100 MB 檔,使用者手動確認才刪
- [ ] 舊版 Windows.old(如有,通常在主要更新後產生)
- [ ] Hover / Pagefile 調整(只在 SSD 空間極度緊張才動)
- [ ] 驗收:VS/Docker/瀏覽器都正常運作
階段 D — 不動(絕對禁止)
- C:\Windows\System32、登錄檔、driver store、UWP apps 的 Packages
- 任何 Microsoft Store 安裝的 App
- BitLocker / 還原點
驗收標準:
- [ ] C 槽 free > 30 GB
- [ ] docker run hello-world 成功
- [ ] VS 2022 可正常 build 一個 .NET 專案
- [ ] Windows Update 不再報 0x80070070
- [ ] 連續使用 3 天,無藍幕、無程式崩潰
重點:每階段都有「驗收 = 可運作」條件,不只是「釋出空間」。Skill 強調 — 目標是系統正常運作 + 有空間,不是只有空間。
第 3 步:Executing Plans — 階段 A 安全清理
逐項執行,每項執行後記錄前後 delta:
# 記錄 T0
$before = (Get-PSDrive C).Free
# A1: Windows 內建磁碟清理(用 cleanmgr 預設值,不打勾「下載」避免誤刪)
# 用 PowerShell 啟動干净 mgr 的所有安全選項
$volumeCaches = Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches'
foreach ($cache in $volumeCaches) {
# 只啟用「安全」類別,跳過「Downloads」與「Update Backup」(後者等 D 階段手動處理)
if ($cache.PSChildName -in 'Temporary Files','Thumbnail Cache','Temporary Internet Files',
'Delivery Optimization Files','Windows Error Reporting Files',
'Recycle Bin','Previous Installations') {
Set-ItemProperty -Path $cache.PSPath -Name StateFlags0001 -Value 2
}
}
Start-Process cleanmgr -ArgumentList '/sagerun:1' -Wait -Verb RunAs
# 量測 delta
$after = (Get-PSDrive C).Free
"階段 A1 釋放: $([math]::Round(($after - $before) / 1GB, 2)) GB"
A2:WinSxS 壓縮(Windows 元件存放區,通常 5-10 GB,可壓縮一半,但需要管理員)
# 分析前先看現狀
Dism /Online /Cleanup-Image /AnalyzeComponentStore
# Output:
# Component Store Cleanup Recommended : Yes
# Actual Backup Size : 7.8 GB
# 執行清理(這是安全指令,Microsoft 官方支援)
Dism /Online /Cleanup-Image /StartComponentCleanup
# 清完後再 Analyze,Backup Size 應降至 ~4 GB
# 進階版: ResetBase(把所有舊版元件替換點合併,無法解除安裝之前的更新)
# ⚠️ 這個會讓你未來無法 uninstall 已安裝的 Windows Update
# 只在「絕對不會回滾 Windows Update」的場景才用
Dism /Online /Cleanup-Image /StartComponentCleanup /ResetBase
⚠️ ResetBase 的取捨:
/ResetBase多釋 1-2 GB,代價是「未來無法 uninstall 已安裝的 Windows Update」。本範例不建議使用,除非是部署映像階段。
第 4 步:Executing Plans — 階段 B 開發機 dev cache
這是 Windows 開發機最大、最重複的浪費來源。
# B1: Node.js cache(npm 與 pnpm 分開)
npm cache clean --force 2>&1 | Out-Null
pnpm store prune 2>&1 | Out-Null
# 釋放通常 2-5 GB
# B2: .NET NuGet 與 build cache
dotnet nuget locals all --clear
# 釋放 ~3 GB(取決於你裝過多少套件)
# 清所有專案的 bin/obj (用一個 PowerShell 腳本)
Get-ChildItem -Path C:\Users\<你>\source -Recurse -Directory -Include 'bin','obj' -ErrorAction SilentlyContinue |
Where-Object { $_.FullName -notmatch '\\node_modules\\' } | # 跳過 node 內的 bin/obj 偽陽性
Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
# 釋放 3-10 GB,可重建
# B3: pip / Python cache
pip cache purge 2>&1 | Out-Null
# B4: VS 2022 cache (ComponentModelCache 與 BackupFiles)
Remove-Item "$env:LOCALAPPDATA\Microsoft\VisualStudio\17.*\ComponentModelCache" -Recurse -Force -EA SilentlyContinue
Remove-Item "$env:LOCALAPPDATA\Microsoft\VisualStudio\17.*\BackupFiles" -Recurse -Force -EA SilentlyContinue
# B5: Docker(最謹慎,可能有 local 開發的 image 捨不得)
docker system df # 先看現狀
# RECLAIMABLE 欄位就是可清的
docker system prune -a --volumes --filter "until=168h"
# ↑ 只清「7 天前沒被用過」的,正在用的 image 會被保留
# 不要直接 docker system prune -a --volumes(會清掉所有沒有 container 引用的 image)
第 5 步:Verification Before Deletion — 階段 C dry-run
「Downloads 釋放空間最容易出事」— 使用者珍藏的安裝檔、影片解析度,誤刪難復原。先用 dry-run 列出,使用者確認才刪:
# C1: 大於 100 MB 的 Downloads 列表(不刪,只列出)
Get-ChildItem "$env:USERPROFILE\Downloads" -Recurse -File -EA SilentlyContinue |
Where-Object Length -gt 100MB |
Sort-Object Length -Descending |
Select-Object @{n='MB';e={[math]::Round($_.Length/1MB,1)}},
@{n='Modified';e={$_.LastWriteTime.ToString('yyyy-MM-dd')}},
FullName |
Format-Table -AutoSize
# 預期輸出(範例):
# MB Modified FullName
# -- -------- --------
# 842.5 2025-03-12 ...\VS2022_Enterprise.iso
# 612.0 2024-11-08 ...\node-v20.10.0-x64.msi
# 198.3 2026-01-22 ...\adobe-acrobat-pro.exe
# ...
# 使用者看清單後手動確認:這個 iso 還需要嗎? msi 是不是裝完了?
# 確認後用 Out-GridView -PassThru 讓使用者勾選
$toDelete = Get-ChildItem "$env:USERPROFILE\Downloads" -Recurse -File -EA SilentlyContinue |
Where-Object Length -gt 100MB |
Out-GridView -Title "勾選要刪除的項目(其餘會保留)" -PassThru
# ⚠️ 雙重確認
if ($toDelete) {
$totalMB = [math]::Round(($toDelete | Measure-Object Length -Sum).Sum / 1MB, 1)
$msg = "即將刪除 $($toDelete.Count) 個檔案,共 $totalMB MB。`n這些檔案會進資源回收桶(可復原)。`n`n確認嗎?"
if ((Get-CimInstance Win32_UserDesktop -Filter "Name='$env:USERPROFILE'" -EA SilentlyContinue) -or
[System.Windows.MessageBox]::Show($msg, '確認刪除', '.YesNo', 'Warning') -eq 'Yes') {
$toDelete | Remove-Item -Force # 預設會進回收桶而不是永久刪
}
}
關鍵模式:
- 列出 → 互動確認 → 才刪 — 不寫
[Remove-Item]自動跑 - 進回收桶而非永久刪 — 即使確認錯了也可挽回
- 超大檔 + 逾 30 天未動 — 才敢推薦 — 不是「> 100MB 就刪」
第 6 步:Verification Before Completion — 全面驗收
觸發:
使用 verification-before-completion skill 確認清理後系統運作正常,且釋放目標達標
驗收清單(三面向:空間 + 功能 + 安全):
✅ 空間達標(目標:free > 30 GB)
- T0 基線:1.8 GB free
- T_final:32.4 GB free ✓ (釋放 30.6 GB,目標達標)
- 各階段 delta 記錄在清理 log,可追溯
✅ 功能正常運作(目標:不影響日常)
- VS 2022 開啟並 build 一個 .NET 9 專案:< 30 秒編譯、零錯誤 ✓
- Docker run hello-world:成功 ✓
- npm install 在隨意專案:成功(cache 會自動重建)✓
- Windows Update 不再報 0x80070070(安裝上月累積更新成功)✓
- 開發機重開 3 次都正常進 OS ✓
✅ 安全確認(目標:可逆、無系統風險)
- 階段 C 刪除的 Downloads 仍在資源回收桶(7 天保留期)✓
- 階段 A/B 清掉的都是可重建的 cache,git/dotnet/docker 都能重新拉取 ✓
- 系統還原點未被刪除(后期若出問題可 revert)✓
- 未動 C:\Windows 與登錄檔 ✓
- 連續使用 3 天後無藍幕 / 無程式崩潰 ✓
✅ 維運長期化
- 排程每月 1 號自動跑「階段 A + B」PowerShell 腳本 ✓
- Visual Studio 設定「關閉時清 ComponentModelCache」啟用 ✓
- Docker Desktop 設定「每天 prune 未用資源」啟用 ✓
第 7 步:Defense in Depth — 防止再肥
清一次只能解一時,長期得靠自動化。把階段 A+B 寫成一個 clean-dev-cache.ps1:
# clean-dev-cache.ps1 — 每月 1 號排程執行
#Requires -RunAsAdministrator
$ErrorActionPreference = 'SilentlyContinue'
$log = "$env:USERPROFILE\clean-dev-cache.log"
"=== $(Get-Date) ===" | Out-File $log -Append
function Log-Size($label) {
$free = [math]::Round((Get-PSDrive C).Free / 1GB, 2)
"$label : C 槽可用 $free GB" | Out-File $log -Append
}
Log-Size 'T0 開始'
# 階段 A:系統清理
Start-Process cleanmgr -ArgumentList '/sagerun:1' -Wait
Dism /Online /Cleanup-Image /StartComponentCleanup | Out-Null
Log-Size '階段 A 完成'
# 階段 B:開發 cache
npm cache clean --force
pnpm store prune
dotnet nuget locals all --clear
Get-ChildItem "$env:USERPROFILE\source\repos" -Directory |
ForEach-Object {
Get-ChildItem $_.FullName -Recurse -Directory -Include 'bin','obj' |
Remove-Item -Recurse -Force
}
docker system prune -a --volumes --filter 'until=168h' -f
Log-Size '階段 B 完成'
# Task Scheduler 每月 1 日 02:00 執行
# schtasks /create /tn "CleanDevCache" /tr "pwsh -File clean-dev-cache.ps1" `
# /sc monthly /d 1 /st 02:00 /rl highest
重點:/rl highest(管理員)、02:00(沒人用電腦時)、monthly /d 1(每月 1 號)— 自動化跑一次能維持 10-15 GB 的釋放節奏,避免 C 槽再次見底。
關鍵學習點
1. 清理是「根因調查」,不是「動手刪除」
最致命反模式是:「C 槽滿了 → 開磁碟清理 → 按 OK → 重開機 → 還是不夠」。 正確做法:先量測每一層的大小,找出真正肥肉,否則你清了 1 GB 的 Temp、卻忽略 15 GB 的 Docker images。
2. 安全清理 ≠ 全面清理
「最大化釋放空間」與「不影响系統運作」是兩個目標(題目本身就有張力)。Superpowers 的價值在於把這兩個目標都列出來,逐項驗收,不為了衝數字而犧牲安全。/ResetBase 可多釋 2 GB,但會破壞 Windows Update 解除安裝能力 — 這樣的取捨要顯式記錄,不是默默做掉。
3. Dry-Run + 互動確認是不可妥協的
階段 C 範例示範了 Out-GridView -PassThru + MessageBox 的「真正互動確認」。不可寫 Get-ChildItem ... | Remove-Item -Force 的自動批次刪除(在使用者家目錄下),這跟「為了蝦子燒掉海」沒兩樣。
4. Dev cache 才是真正的長期元兇
Windows 內建 Temp 一次只佔幾 GB,但 N 個 node_modules + N 個 bin/obj + NuGet packages + pnpm-store 在 N 個專案下會默默累積到 30+ GB。 身為開發者,這部分要每月定期清,否則重灌 Windows 也撐不了半年。
5. Verification skill 在運維場景更關鍵
寫程式時 Verification 是「測試通過」,運維時 Verification 是「系統還能正常運作」。後者更嚴苛 — 因為後果可能是藍幕 / 開不了機 / 無法登入。本範例每階段都驗「VS / Docker / Windows Update / 重開機」,這是對「不影响系統運作」紅線的兌現。
工具使用摘要
| Skill | 用途 | 在本例的作用 |
|---|---|---|
| Systematic Debugging | 根因調查 | 多層目錄量測,找出 AppData、Docker、NuGet |
| Writing Plans | 拆解計畫 | A(系統)/B(dev cache)/C(謹慎)/D(禁動)四級風險 |
| Executing Plans | 逐層執行 | 每階段記錄 delta、不跳階 |
| Verification Before Completion | 全面驗收 | 空間 + 功能 + 安全 + 維運四面向 |
| Defense in Depth(輔助) | 防退化 | 每月排程、開發工具內建清理啟用 |
總結
C 槽清理看似「運維任務」,但其核心過程與寫程式 debug 完全同構:
- 量測優先:不量測就動手是猜測式修復(= 反 Systematic Debugging)
- 分類風險:Level A/B/C/D 是把「風險」結構化(= Writing Plans 強制思考)
- dry-run + 確認:互動式刪除是 verification 的延伸
- 防退化:排程自動化是 defense-in-depth 的工程落地
最關鍵的: 「最大化釋放空間」與「不影响系統運作」是兩個目標,不是一個。Superpowers skills 強迫你把這兩個目標都列出來、都驗收,避免為了衝數字而清出未來的藍幕。
下次當 C 槽只剩 2 GB,先別開磁碟清理,先量測。