לדלג לתוכן

פתרון אחיזה ודליפה לוגית

ה־cache הבא מוגבל במספר ערכים ומגדיר שעדכון אינו משנה סדר. המבנה מתאים לחוזה חד־תהליכי ומפנה references בלי לבקש פעולה מיוחדת מן ה־GC.

var cache = new BoundedCache<int, byte[]>(32);
for (int i = 0; i < 1_000; i++) cache.Put(i, new byte[1024]);
Console.WriteLine(cache.Count);

sealed class BoundedCache<TKey, TValue> where TKey : notnull
{
    private readonly int capacity;
    private readonly Dictionary<TKey, TValue> values = new();
    private readonly Queue<TKey> order = new();
    public int Count => values.Count;
    public BoundedCache(int capacity)
    {
        if (capacity <= 0) throw new ArgumentOutOfRangeException(nameof(capacity));
        this.capacity = capacity;
    }
    public void Put(TKey key, TValue value)
    {
        if (values.ContainsKey(key)) { values[key] = value; return; }
        if (values.Count == capacity) values.Remove(order.Dequeue());
        values.Add(key, value);
        order.Enqueue(key);
    }
}

הפלט 32 מוכיח את מגבלת מספר הפריטים בתרחיש, אבל לא מגבלת byte-ים: ערך אחד יכול להיות גדול מאוד. אם המוצר דורש תקציב זיכרון נוסיף משקל ידוע של כל ערך ובדיקת סכום לפני קבלה. קיבולת פנימית של Dictionary או Queue יכולה להישאר גם אחרי הסרת איברים, וזה שימוש בזיכרון שיש למדוד בנפרד מן payload-ים שממשיכים להיות נגישים.

המסלול של האירוע מתחיל בשדה סטטי, עובר דרך invocation list ו־delegate אל subscriber. התיקון הוא ניתוק ההרשמה או שינוי מודל הבעלות. קריאה נוספת ל־GC.Collect אינה מנתקת reference חזק. מדידת allocated bytes סופרת תנועה של הקצאות לאורך זמן, heap חי מתאר אובייקטים שנשמרו, ו־working set כולל דפים שנמצאים כרגע בזיכרון הפיזי עבור התהליך, לרבות רכיבים שאינם heap מנוהל.