פינוי של 50-100 GB בבטחה: מדריך ניקוי דיסק מלא למפתחי .NET, מנועי משחקים ותוכנות שולחניות
כל מפתח תוכנה ומשחקים בסביבת Windows נתקל במוקדם או במאוחר באותו בוקר מסויט: אתם מדליקים את תחנת העבודה, פותחים את סביבת הפיתוח (IDE), ולפתע Windows מציגה התראה אדומה—בכונן ה-SSD NVMe בנפח 1 TB נותרו פחות מ-2 GB של מקום פנוי.
לא הורדתם סרטים כבדים, ולא התקנתם משחקים חדשים של 100 GB. לאן נעלם כל נפח האחסון?
כמפתח משחקי אינדי ואפליקציות שולחניות מרובות פלטפורמות ב-.NET 8/9, MonoGame, Android / Mobile ו-Windows Application Packaging (MSIX/WAP עבור Microsoft Store), חקרתי לעומק את משבר האחסון השקט הזה. בתוך דקות ספורות של סריקה אוטומטית בכל מאגרי הפרויקטים שלי, גיליתי שמעל 68 GB נתפסו לחלוטין על ידי תוצרי בנייה זמניים, חבילות הפצה ישנות ומטמוני חבילות מיותרים.
במדריך זה נפרק את הסיבות הארכיטקטוניות לכך שכלי פיתוח מודרניים צורכים כמויות עצומות של זיכרון, נסביר מדוע מחיקת היעדים הללו היא בטוחה ב-100%, ונשתף כלי אוטומטי מבוסס PowerShell ו-Batch שניתן להפעיל בכל פרויקט כדי לשחרר עשרות גיגה-בייט באופן מיידי.
1. האנטומיה של התנפחות הדיסק אצל מפתחים
לאן נעלם כל האחסון? בעת בניית פתרונות מרובי פלטפורמות המכוונים למחשב שולחני, למובייל (Android) ול-Microsoft Store, מהדרים וכלי אריזה משכפלים קבצים בינאריים ונכסי משחק בכל שלב ושלב:
flowchart TD
subgraph "סביבת העבודה של הפרויקטים"
Code["קוד מקור (.cs, .xaml, .json)\n(מוגן - מגה-בייטים בודדים)"]
Assets["נכסי מקור (PNG, OGG, Shaders)\n(מוגן)"]
Git["היסטוריית .git\n(מוגן)"]
BinObj["תיקיות bin ו-obj\n(קבצי DLL זמניים, סמלים, עותקים)\n[30 - 60 GB]"]
AppPackages["WAP / MSIX AppPackages\n(חבילות חנות היסטוריות)\n[5 - 20 GB]"]
end
subgraph "מטמוני מערכת וגלובליים"
NuGet["%USERPROFILE%\\.nuget\\packages\n(מטמון NuGet גלובלי)\n[10 - 20 GB]"]
Temp["%LOCALAPPDATA%\\Temp\n(קבצי מהדר זמניים, יומנים)\n[3 - 10 GB]"]
end
style BinObj fill:#ff6b6b,stroke:#c92a2a,stroke-width:2px,color:#fff
style AppPackages fill:#ff6b6b,stroke:#c92a2a,stroke-width:2px,color:#fff
style NuGet fill:#ff922b,stroke:#d9480f,stroke-width:2px,color:#fff
style Temp fill:#ff922b,stroke:#d9480f,stroke-width:2px,color:#fff
אשם א': תיקיות bin ו-obj (נפח של 30 עד 60+ GB)
כל פרויקט C# מייצר שתי תיקיות במהלך ההידור:
obj/(פלט ביניים): שומר את מצב ההידור ההדרגתי (Incremental Build), קבצים שנוצרו על ידי מחוללי מקור (Source Generators), ותוצרי ביניים ייעודיים לפלטפורמה. בפרויקטים המכוונים למספר יעדים (למשלnet9.0-windows10.0ו-net9.0-android), קבצי הביניים של אנדרואיד לבדם מגיעים ל-3 עד 6 GB לפרויקט בודד.bin/(פלט בינארי): מכיל את קבצי ההרכבה הסופיים (DLLs), תלויות זמן ריצה וכל נכסי המשחק המועתקים באמצעות<CopyToOutputDirectory>. אם יש לכם 10 פרויקטים המפנים לתיקיית נכסי משחק משותפת בנפח 500 MB, תוכן זה מועתק 10 פעמים, ומבזבז 5 GB עבור פתרון אחד בלבד!
אשם ב': תיקיות AppPackages של חנות מיקרוסופט (5 עד 20+ GB)
אם אתם מפרסמים משחקים או אפליקציות שולחניות ל-Microsoft Store באמצעות פרויקט אריזה (WAP), Visual Studio מייצרת תיקיית AppPackages:
- כל גרסה מייצרת חבילת
.msixbundleמלאה, קובץ.msixupload(המכיל קבצים בינאריים מלאים וסמלי ניפוי שגיאות PDB לדיווח על קריסות), ותיקיות התקנה עצמאיות לבדיקה. - חבילת הפצה יחידה שוקלת לרוב בין 800 MB ל-2.5 GB. אם אתם בונים 10 גרסאות בדיקה או טלאים, Visual Studio לעולם אינה מוחקת את הגרסאות הישנות באופן אוטומטי. הן נשארות בדיסק לנצח.
אשם ג': מטמון החבילות הגלובלי של NuGet (נפח של 10 עד 20+ GB)
במיקום %USERPROFILE%\.nuget\packages, ספריה זו שומרת כל גרסה של כל חבילת NuGet שהורדה אי פעם במחשבכם. אם ספרייה מתעדכנת מגרסה 12.0.1 ל-12.0.2, הגרסה הישנה נשארת שמורה לנצח אלא אם היא מנוקה ידנית.
אשם ד': קבצי המערכת הזמניים של Windows (נפח של 3 עד 10 GB)
במהלך תהליכי הידור, אריזה ודחיסת נכסים, כלי MSBuild ו-Visual Studio מחלצים אלפי קבצים זמניים לתיקיית %LOCALAPPDATA%\Temp.
2. הבטחת בטיחות: מדוע הניקוי נטול סיכון ב-100%?
מפתחים נוהגים בזהירות מוצדקת לפני מחיקת קבצים. הכלל הבא מבהיר באופן מוחלט מה מוגן ומה בטוח למחיקה:
| מוגן (לעולם אינו נמחק) | בטוח למחיקה (100% בר-שחזור) |
|---|---|
קוד מקור: .cs, .xaml, .cpp, .h, .ts, .json |
קבצי אובייקט זמניים של המהדר (obj/) |
הגדרות פרויקט ופתרון: .sln, .csproj, .wapproj |
קבצים בינאריים וספריות מהודרות (bin/) |
מאגרי Git: תיקיית .git/, ענפים, היסטוריית קומיטים |
חבילות הפצה ישנות לחנות (AppPackages/) |
נכסי מקור גולמיים: טקסטורות (.png), שמע (.ogg), שיידרים |
חבילות NuGet שמורות במטמון (.nuget\packages) |
תעודות והגדרות חנות: .pfx, StoreAssociation.xml |
קבצי עבודה זמניים של המערכת (%LOCALAPPDATA%\Temp) |
מה קורה כשפותחים מחדש את Visual Studio?
ברגע שאתם פותחים את הפרויקט ולוחצים על Build או Rebuild, כלי ה-SDK של .NET יוצרים מחדש את תיקיותobj/ו-bin/ישירות מקוד המקור שלכם. מנהל החבילות NuGet מוריד אוטומטית את התלויות החסרות. שום הגדרה ושום קוד אינם הולכים לאיבוד.
3. הפתרון האוטומטי: סקריפט ניקוי בלחיצת כפתור
במקום לחפש ידנית בין מאות תיקיות, יצרנו מנוע PowerShell עצמאי ומפעיל Batch ייעודי.
מנוע הניקוי ב-PowerShell (Clean-DevDiskSpace.ps1)
שמרו סקריפט זה בתיקיית כלים (למשל _tools/Clean-DevDiskSpace.ps1):
<#
.SYNOPSIS
Universal Developer Disk Space Cleanup Tool.
.DESCRIPTION
Scans and safely purges temporary build artifacts (bin/obj), Microsoft Store
packaging output (AppPackages), Windows Temp files, and local NuGet caches.
Source code, git tracking, assets, and project definitions are 100% protected.
#>
[CmdletBinding()]
param (
[switch]$Force,
[switch]$ScanOnly,
[switch]$SkipNuget,
[switch]$SkipTemp,
[string]$RootPath = ""
)
if ([string]::IsNullOrWhiteSpace($RootPath)) {
if ($PSScriptRoot) { $RootPath = (Join-Path $PSScriptRoot "..") } else { $RootPath = Get-Location }
}
$resolvedRoot = (Resolve-Path $RootPath -ErrorAction SilentlyContinue).Path
if ([string]::IsNullOrWhiteSpace($resolvedRoot) -or $resolvedRoot -in @("C:\", "C:", "\", "/")) {
Write-Host "SAFETY ABORT: Target path is empty or a root drive! Aborting operation." -ForegroundColor Red
exit 1
}
$Host.UI.RawUI.WindowTitle = "Developer Workspace Disk Cleanup"
Write-Host "================================================================================" -ForegroundColor Cyan
Write-Host " DEVELOPER WORKSPACE DISK CLEANUP TOOL " -ForegroundColor Cyan
Write-Host "================================================================================" -ForegroundColor Cyan
Write-Host "Target Workspace: $resolvedRoot" -ForegroundColor Yellow
function Get-FolderSizeInfo {
param ([string]$Path)
if (-not (Test-Path $Path)) { return @{ SizeMB = 0; SizeGB = 0; Count = 0 } }
$measure = Get-ChildItem -Path $Path -Recurse -File -Force -ErrorAction SilentlyContinue |
Measure-Object -Property Length -Sum
$sum = if ($measure.Sum) { $measure.Sum } else { 0 }
return @{
SizeMB = [math]::Round($sum / 1MB, 2)
SizeGB = [math]::Round($sum / 1GB, 2)
Count = $measure.Count
}
}
$systemDrive = Get-PSDrive -Name C
$freeGBBefore = [math]::Round($systemDrive.Free / 1GB, 2)
Write-Host "`nCurrent Free Space on C: $freeGBBefore GB`n" -ForegroundColor Yellow
Write-Host "[1/4] Scanning project 'bin' and 'obj' directories..." -ForegroundColor Green
$binObjDirs = Get-ChildItem -Path $resolvedRoot -Recurse -Directory -Force -ErrorAction SilentlyContinue |
Where-Object { $_.Name -in @('bin', 'obj') }
$binObjTotalBytes = 0
$binObjCount = 0
foreach ($dir in $binObjDirs) {
$m = (Get-ChildItem -Path $dir.FullName -Recurse -File -Force -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum).Sum
if ($m) { $binObjTotalBytes += $m }
$binObjCount++
}
$binObjGB = [math]::Round($binObjTotalBytes / 1GB, 2)
Write-Host "[2/4] Scanning Microsoft Store / MSIX 'AppPackages' directories..." -ForegroundColor Green
$appPackageDirs = Get-ChildItem -Path $resolvedRoot -Recurse -Directory -Filter "AppPackages" -Force -ErrorAction SilentlyContinue
$storeTotalBytes = 0
$storeCount = 0
foreach ($dir in $appPackageDirs) {
$m = (Get-ChildItem -Path $dir.FullName -Recurse -File -Force -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum).Sum
if ($m) { $storeTotalBytes += $m }
$storeCount++
}
$storeGB = [math]::Round($storeTotalBytes / 1GB, 2)
Write-Host "[3/4] Calculating Windows Temp folder size..." -ForegroundColor Green
$tempPath = [System.IO.Path]::GetTempPath()
$tempInfo = if (-not $SkipTemp) { Get-FolderSizeInfo -Path $tempPath } else { @{ SizeGB = 0; Count = 0 } }
Write-Host "[4/4] Calculating local NuGet cache size..." -ForegroundColor Green
$nugetCachePath = "$env:USERPROFILE\.nuget\packages"
$nugetInfo = if (-not $SkipNuget) { Get-FolderSizeInfo -Path $nugetCachePath } else { @{ SizeGB = 0; Count = 0 } }
$totalReclaimableGB = [math]::Round($binObjGB + $storeGB + $tempInfo.SizeGB + $nugetInfo.SizeGB, 2)
Write-Host "`n========================= IDENTIFIED RECLAIMABLE STORAGE =========================" -ForegroundColor Magenta
$scanSummary = @(
[PSCustomObject]@{ Target = "Project Build Artifacts (bin/obj)"; Folders = $binObjCount; PotentialSavings = "$binObjGB GB" },
[PSCustomObject]@{ Target = "Microsoft Store Bundles (AppPackages)"; Folders = $storeCount; PotentialSavings = "$storeGB GB" },
[PSCustomObject]@{ Target = "Windows Temporary Files (Temp)"; Folders = $tempInfo.Count; PotentialSavings = "$($tempInfo.SizeGB) GB" },
[PSCustomObject]@{ Target = "Local NuGet Package Cache"; Folders = $nugetInfo.Count; PotentialSavings = "$($nugetInfo.SizeGB) GB" }
)
$scanSummary | Format-Table -AutoSize
Write-Host ">>> TOTAL ESTIMATED RECLAIMABLE SPACE: $totalReclaimableGB GB <<<`n" -ForegroundColor Cyan
if ($ScanOnly) {
Write-Host "Scan-only mode completed. No files removed." -ForegroundColor Yellow
return
}
if (-not $Force) {
$prompt = Read-Host "Do you want to proceed with purging these files? (Y/N)"
if ($prompt -notin @('Y', 'y', 'Yes', 'yes')) {
Write-Host "Cleanup cancelled." -ForegroundColor Yellow
return
}
}
Write-Host "`n>>> Starting cleanup... Please wait...`n" -ForegroundColor Cyan
# 1. Delete bin and obj
$binObjDirs | ForEach-Object { try { Remove-Item -Path $_.FullName -Recurse -Force -ErrorAction SilentlyContinue } catch {} }
# 2. Delete AppPackages
$appPackageDirs | ForEach-Object { try { Remove-Item -Path $_.FullName -Recurse -Force -ErrorAction SilentlyContinue } catch {} }
# 3. Clean Temp
if (-not $SkipTemp) {
Get-ChildItem -Path $tempPath -Force -ErrorAction SilentlyContinue | ForEach-Object {
try { Remove-Item -Path $_.FullName -Recurse -Force -ErrorAction SilentlyContinue } catch {}
}
}
# 4. Clean NuGet
if (-not $SkipNuget) {
try { $null = dotnet nuget locals all --clear 2>&1 } catch {}
}
$systemDriveAfter = Get-PSDrive -Name C
$freeGBAfter = [math]::Round($systemDriveAfter.Free / 1GB, 2)
$freedTotal = [math]::Round($freeGBAfter - $freeGBBefore, 2)
Write-Host "`n================================================================================" -ForegroundColor Green
Write-Host " CLEANUP COMPLETED! " -ForegroundColor Green
Write-Host "================================================================================" -ForegroundColor Green
Write-Host "Free Space Before : $freeGBBefore GB" -ForegroundColor White
Write-Host "Free Space After : $freeGBAfter GB" -ForegroundColor Green
Write-Host "Total Reclaimed : +$freedTotal GB" -ForegroundColor Cyan
Write-Host "================================================================================`n" -ForegroundColor Green
קובץ הפעלה מהיר (clean-disk-space.bat)
@echo off
setlocal
title Developer Workspace Disk Cleanup
cd /d "%~dp0"
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dp0_tools\Clean-DevDiskSpace.ps1" %*
pause
4. תוצאות אמת מהשטח: מ-1.35 GB ל-53.80 GB
בבדיקת אמת שנערכה בסביבת עבודה המכילה מנועי משחקים, פרויקטים שולחניים ואפליקציות מובייל:
- מקום פנוי לפני הניקוי: 1.35 GB (מצב התראה קריטי)
- מקום פנוי לאחר הניקוי: 53.80 GB
- נטו שטח ששוחרר: +52.45 GB בפחות מ-3 דקות.
5. המלצות לתחזוקת דיסק קבועה
- ניקוי לאחר כל העלאה לחנות: לאחר שהחבילה מתקבלת ב-Microsoft Partner Center או Google Play, מחקו את תיקיית
AppPackagesהמקומית. - הפעלה שגרתית פעם בחודש: הפעלה קצרה מונעת הצטברות זוחלת של עשרות גיגה-בייט.
- הגדרת
.gitignoreמוקפדת: ודאו שכללי ההתעלמות כולליםbin/,obj/ו-AppPackages/.
אודות Arar Games והמשחקים שלנו
גלו את משחקי האינדי שלנו והתחברו לסטודיו:
- 🌐 אתר רשמי (Official Website): https://www.mayhemcorporation.com
🎮 המשחקים שלנו
- Blocked: Pixel Panzer: קרבות טנקים רטרו-ארקייד עם מזג אוויר דינמי ובוסים עוצמתיים.
Google Play (Android & PC) - PaintTrek: חידות צבעים מרהיבות ואקשן צביעת פיקסלים מהיר.
Google Play | Microsoft Store (PC & Xbox) - Space Dodger: התחמקות ממכשולים בחלל במהירות גבוהה לבחינת רפלקסים.
Google Play
📱 עקבו אחרי הסטודיו ברשתות החברתיות
- 🎵 TikTok: https://www.tiktok.com/@arargamesstudio
- 📸 Instagram: https://www.instagram.com/arargamesstudio
- 🐦 X (Twitter): https://x.com/arargamesstudio
- 📺 YouTube: https://www.youtube.com/@koreaaria
- 🧵 Threads: https://www.threads.net/@arargamesstudio
- 📘 Facebook: https://www.facebook.com/arargamesstudio
Hiç yorum yok:
Yorum Gönder