לדלג לתוכן

פתרון העתקות והקצאות

העתקת המערך אינה מתרחשת כחלק מהעתקת Packet. התוכנית הבאה שומרת שיתוף מפורש, ומודדת רק את בניית הרשימות וה־boxing שלהן.

var bytes = new byte[] { 1 };
var a = new Packet(10, bytes);
var b = a;
b.Number = 20;
b.Bytes[0] = 9;
Console.WriteLine($"{a.Number}, {b.Number}, {a.Bytes[0]}");

Measure(bytes, false);
Measure(bytes, true);
Console.WriteLine($"typed={Measure(bytes, false)}");
Console.WriteLine($"boxed={Measure(bytes, true)}");

static long Measure(byte[] shared, bool box)
{
    long before = GC.GetAllocatedBytesForCurrentThread();
    object result;
    if (box)
    {
        var list = new List<object>(100_000);
        for (int i = 0; i < 100_000; i++) list.Add(new Packet(i, shared));
        result = list;
    }
    else
    {
        var list = new List<Packet>(100_000);
        for (int i = 0; i < 100_000; i++) list.Add(new Packet(i, shared));
        result = list;
    }
    long used = GC.GetAllocatedBytesForCurrentThread() - before;
    GC.KeepAlive(result);
    return used;
}

struct Packet(int number, byte[] bytes)
{
    public int Number = number;
    public byte[] Bytes = bytes;
}

הפלט של השינויים הוא 10, 20 ו־9. שתי הרשימות מקצות את האחסון הפנימי שלהן, אבל הרשימה של object מוסיפה boxes לכל איבר. המספר המדויק תלוי ב־layout וביישור, ואינו חלק מחוזה השפה. הסימון string? מוסיף מידע לניתוח הסטטי של הקומפיילר; הטיפוס ממשיך להיות reference type והבדיקות בזמן ריצה אינן הופכות אותו ל־Nullable של value types.