Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> C#

Garbage Collector ใน C# ทำงานอย่างไร - Automatic Memory Management

Garbage Collector (GC) ใน .NET เป็น Automatic Memory Manager จัดการหน่วยความจำ Managed Heap ให้อัตโนมัติ

หลักการทำงานพื้นฐาน

  1. Allocation: `new` Object → 配置บน Managed Heap (Pointer Bump - เร็วมาก)
  2. Root Tracking: GC รู้จัก "Roots" (Stack Variables, Static Fields, CPU Registers)
  3. Mark Phase: Traverse จาก Roots ทุก Object ที่ Reachable = Live
  4. Sweep/Compact Phase: Unreachable = Garbage → Reclaim Memory, Compact Heap
  5. Generations: Gen 0 (New), Gen 1 (Survived 1 GC), Gen 2 (Long-lived)

Generational GC

Generationอายุ Objectความถี่ GCขนาด Heap
Gen 0Short-lived (New Objects)บ่อยมากเล็ก (~256KB-4MB)
Gen 1Survived Gen 0ปานกลางกลาง
Gen 2Long-lived (Static, Large Objects)น้อยใหญ่
LOH>= 85,000 bytesเฉพาะ Gen 2 GCแยกต่างหาก (ไม่ Compact)

ประโยชน์ของ GC

  • ไม่ต้อง Free Memory ด้วยตนเอง (No Manual Memory Management)
  • ป้องกัน Memory Leaks (ส่วนใหญ่), Dangling Pointers, Double Free
  • Allocation เร็วมาก (Pointer Bump - เพียง Increment Pointer)
  • Memory Safety: Type Safety + Bounds Checking
  • Objects ใหม่ได้ Zero-initialized อัตโนมัติ

GC Modes


// Workstation GC (Default for Client Apps) - Low Latency, Concurrent
// Server GC (Default for ASP.NET Core, Services) - High Throughput, Multi-Heap

// Configure in .csproj or runtimeconfig.json

  true 
  true 

GC APIs ที่ควรรู้


// Force GC (ไม่แนะนำให้ใช้บ่อย - ให้ GC จัดการเอง)
GC.Collect();           // Full GC (All Generations)
GC.Collect(2);          // Gen 2 Only
GC.Collect(2, GCCollectionMode.Forced, blocking: true, compacting: true);

// Query Info
int gen = GC.GetGeneration(obj);        // Object Generation
long bytes = GC.GetTotalMemory(false);  // Allocated Bytes (approx)
bool isServer = GCSettings.IsServerGC;  // GC Mode

// Large Object Heap (LOH) Compaction (.NET 4.5.1+)
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect();

IDisposable & Finalizer Pattern


public class ResourceHolder : IDisposable
{
    private IntPtr _unmanagedResource;
    private bool _disposed;

    // Finalizer (Destructor Syntax) - Safety Net
    ~ResourceHolder() => Dispose(false);

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this); // ข้าม Finalizer เพราะ Cleaned แล้ว
    }

    protected virtual void Dispose(bool disposing)
    {
        if (_disposed) return;

        if (disposing)
        {
            // Free Managed Resources
        }

        // Free Unmanaged Resources
        if (_unmanagedResource != IntPtr.Zero)
        {
            Marshal.FreeHGlobal(_unmanagedResource);
            _unmanagedResource = IntPtr.Zero;
        }

        _disposed = true;
    }
}

Best Practices

  • อย่า Force GC ยกเว้น Testing/Profiling/สถานการณ์พิเศษ
  • Implement IDisposable สำหรับ Unmanaged Resources (File, DB, Network, Native)
  • ใช้ `using` / `using var` ให้ Dispose ถูกต้อง
  • หลีกเลี่ยง Finalizer ถ้าไม่จำเป็น (Overhead, Non-deterministic)
  • หลีกเลี่ยง Large Objects ใน Hot Path (LOH Fragmentation)
  • Object Pooling สำหรับ Objects ที่สร้าง/ทิ้งบ่อย (ArrayPool, MemoryPool)

Monitoring GC


// ETW Events, PerfView, dotnet-counters, dotnet-gcdump
dotnet-counters monitor --process-id  System.Runtime
// Gen 0/1/2 GC Count, Heap Size, Allocation Rate, Pause Time