Kiểm toán và triệt tiêu cấp phát bộ nhớ rác (Garbage Collection - GC Allocation) trong Unity 6, hướng tới Zero-GC per frame trong Update loop. Tự động kích hoạt khi chỉnh sửa C# scripts, game loop, physics update, LINQ trong game, hoặc khi phát hiện game bị khựng (GC Spike Freeze / Hitching).
Recursos
1Instal·la
npx skillscat add toanmobile/agent-workbench/unity-gc-audit Instal·la des del registre de SkillsCat.
SKILL.md
Unity C# Zero-GC Allocation & Memory Leak Audit
Kỹ năng chuyên sâu kiểm toán mã nguồn C# trong Unity 6, triệt tiêu triệt để các hành vi cấp phát bộ nhớ rác (GC Alloc) trong vòng lặp từng khung hình, loại bỏ hiện tượng khựng game do Garbage Collector dọn dẹp bộ nhớ (GC Spikes).
Nguyên Tắc Vàng Zero-GC
- Vòng lặp từng khung hình là vùng cấm cấp phát (Frame Loops are Zero-Alloc Zones): Các hàm
Update(),LateUpdate(),FixedUpdate(), coroutines chạy liên tục và callbacks render không được phép sinh ra dù chỉ 1 byte GC Allocation. - GC Spike = Giết chết trải nghiệm người dùng: Trong Unity Mono/IL2CPP, việc GC thu gom bộ nhớ sẽ tạm dừng toàn bộ game thread (Stop-The-World), gây tụt khung hình đột ngột (Spike Drop) từ 60/120 FPS về 0 FPS trong vài mili-giây.
- Tái sử dụng & Tiền cấp phát (Pre-allocate & Pool): Mọi đối tượng, bộ đệm, mảng, danh sách phải được tạo sẵn khi tải màn chơi (Loading Phase) hoặc sử dụng Object Pooling.
🔍 Danh Mục Kiểm Toán Mã Nguồn (Audit Checklist)
1. Triệt Tiêu LINQ & Foreach Trên Collection Không Có Struct Enumerator
- ❌ Anti-Pattern: Dùng LINQ (
.Where(),.Select(),.ToList(),.Any()) hoặcforeachtrên interfaces trong frame update:void Update() { var enemies = allUnits.Where(u => u.IsAlive).ToList(); // Cấp phát Iterator & List mới mỗi frame! } - ✅ Chuẩn Senior: Dùng vòng lặp
fortheo chỉ số với danh sách đã cấp phát sẵn hoặc dùng mảng:void Update() { aliveUnits.Clear(); for (int i = 0; i < allUnits.Count; i++) { if (allUnits[i].IsAlive) aliveUnits.Add(allUnits[i]); } }
2. Triệt Tiêu Boxing / Unboxing
- ❌ Anti-Pattern: Ép kiểu struct sang
object, format chuỗi string trong Update, hoặc dùngstring.Format:void Update() { scoreText.text = "Score: " + score; // Tạo string mới trên Heap mỗi frame! } - ✅ Chuẩn Senior:
- Dùng
StringBuildertĩnh hoặc bộ đệm ký tự không cấp phát. - Sử dụng enum comparator không boxing hoặc
EqualityComparer<T>.Default.
- Dùng
3. Bộ Đệm Vật Lý Không Cấp Phát (NonAlloc Physics APIs)
- ❌ Anti-Pattern: Gọi
Physics.RaycastAll()hoặcPhysics.OverlapSphere():RaycastHit[] hits = Physics.RaycastAll(ray, distance); // Trả về mảng mới mỗi lần gọi! - ✅ Chuẩn Senior: Sử dụng phiên bản NonAlloc với mảng kết quả tiền cấp phát:
private static readonly RaycastHit[] s_HitBuffer = new RaycastHit[16]; int hitCount = Physics.RaycastNonAlloc(ray, s_HitBuffer, distance);
4. Tối Ưu Hóa Coroutines & Yield Instructions
- ❌ Anti-Pattern:
yield return new WaitForSeconds(0.5f);tạo instance mới mỗi lần lặp:IEnumerator PulseRoutine() { while (true) { yield return new WaitForSeconds(1.0f); // 20-30 bytes GC Alloc mỗi giây } } - ✅ Chuẩn Senior: Cache instance hoặc dùng biến thời gian tĩnh:
private static readonly WaitForSeconds s_WaitOneSecond = new WaitForSeconds(1.0f); IEnumerator PulseRoutine() { while (true) { yield return s_WaitOneSecond; // Zero GC Alloc } }
5. Hủy Đăng Ký C# Events & Delegates (Chống Rò Rỉ Khi Chuyển Scene)
- ❌ Anti-Pattern: Đăng ký sự kiện tĩnh nhưng không hủy khi
GameObjectbị hủy:void OnEnable() { GameManager.OnScoreChanged += UpdateUI; } // Thiếu OnDisable -> GameManager giữ tham chiếu tới instance đã Destroy -> Memory Leak! - ✅ Chuẩn Senior: Luôn hủy đăng ký đối xứng trong
OnDisable()hoặcOnDestroy():void OnDisable() { GameManager.OnScoreChanged -= UpdateUI; }
🛠️ Công Cụ Kiểm Tra Hồi Quy & Đánh Giá Tự Động
Unity Profiler CPU / Memory Allocation Audit:
bash .agents/active-profile/scripts/unity-batch.sh editmode --category MemoryProfiler- Tiêu chuẩn:
GC.Alloctrong hàmUpdate()ghi nhận bằng 0 B (Zero Bytes).
- Tiêu chuẩn:
Kiểm Tra Rò Rỉ Chuyển Scene (Scene Load/Unload):
bash .agents/active-profile/scripts/unity-batch.sh playmode --category SceneTransition- Tiêu chuẩn: Sau khi dỡ bỏ màn chơi (
Resources.UnloadUnusedAssets()), không còn tham chiếu tĩnh nào trỏ đến đối tượng đã bị phá hủy.
- Tiêu chuẩn: Sau khi dỡ bỏ màn chơi (
Tham chiếu on-demand (nạp khi cần)
references/gameplay-patterns.md— mẫu thiết kế gameplay (State, Command, Observer/Event Bus, Pool, Dirty Flag, Spatial Partition…), ScriptableObject Architecture, bẫy từng mẫu. Rule ngắn:game-rules.md§7.references/unity-ui-motion-qa.md— gói UI uGUI (UIEffect, UIParticle, SoftMask), tween không cấp phát (PrimeTween/LitMotion so với DOTween), QA bot, bảng đối chiếu tuyên bố và giấy phép. Rule ngắn:game-rules.md§3–§6.references/dod-and-render-debug.md— Data-Oriented Design rút từ EnTT cho Unity, quy trình triage lỗi render bằng RenderDoc (kể cả giới hạn Metal/GLES).