Megosztás a következőn keresztül:


Oktatóanyag: Memóriafoglalások ref csökkentése biztonsággal

A .NET-alkalmazások teljesítményhangolása gyakran két technikát is magában foglal. Először csökkentse a halomfoglalások számát és méretét. Másodszor csökkentse az adatok másolásának gyakoriságát. A Visual Studio nagyszerű eszközöket biztosít, amelyekkel elemezheti, hogyan használja az alkalmazás a memóriát. Miután megállapította, hogy az alkalmazás hol végez szükségtelen foglalásokat, módosításokat hajt végre a foglalások minimalizálása érdekében. Típusokat típusokká struct alakíthat átclass. Biztonsági funkciókkal ref megőrizheti a szemantikát, és minimalizálhatja a felesleges másolást.

Használja a Visual Studio 17.5-öt az oktatóanyag legjobb élményéhez. A memóriahasználat elemzéséhez használt .NET-objektumfoglalási eszköz a Visual Studio része. A Visual Studio Code és a parancssor használatával futtathatja az alkalmazást, és elvégezheti az összes módosítást. A módosítások elemzési eredményeit azonban nem fogja látni.

A használni kívánt alkalmazás egy IoT-alkalmazás szimulációja, amely több érzékelőt figyel annak megállapítására, hogy egy betolakodó belépett-e egy titkos gyűjteménybe értékekkel. Az IoT-érzékelők folyamatosan küldenek adatokat, amelyek az oxigén (O2) és a szén-dioxid (CO2) levegőben való kombinációját mérik. A hőmérsékletet és a relatív páratartalmat is jelentik. Ezek az értékek mindig kissé ingadoznak. Azonban, amikor egy személy belép a szobába, a változás egy kicsit több, és mindig ugyanabban az irányban: Oxigén csökken, Szén-dioxid növekszik, hőmérséklet nő, mint a relatív páratartalom. Amikor az érzékelők a növekedés megjelenítéséhez egyesülnek, a betolakodó riasztása aktiválódik.

Ebben az oktatóanyagban futtatja az alkalmazást, méri a memóriafoglalásokat, majd a foglalások számának csökkentésével javítja a teljesítményt. A forráskód a mintaböngészőben érhető el.

A kezdőalkalmazás megismerése

Töltse le az alkalmazást, és futtassa a kezdőmintát. Az indítási alkalmazás megfelelően működik, de mivel sok kis objektumot foglal le minden mérési ciklussal, a teljesítménye lassan csökken az idő múlásával.

Press <return> to start simulation

Debounced measurements:
    Temp:      67.332
    Humidity:  41.077%
    Oxygen:    21.097%
    CO2 (ppm): 404.906
Average measurements:
    Temp:      67.332
    Humidity:  41.077%
    Oxygen:    21.097%
    CO2 (ppm): 404.906

Debounced measurements:
    Temp:      67.349
    Humidity:  46.605%
    Oxygen:    20.998%
    CO2 (ppm): 408.707
Average measurements:
    Temp:      67.349
    Humidity:  46.605%
    Oxygen:    20.998%
    CO2 (ppm): 408.707

Sok sor el lett távolítva.

Debounced measurements:
    Temp:      67.597
    Humidity:  46.543%
    Oxygen:    19.021%
    CO2 (ppm): 429.149
Average measurements:
    Temp:      67.568
    Humidity:  45.684%
    Oxygen:    19.631%
    CO2 (ppm): 423.498
Current intruders: 3
Calculated intruder risk: High

Debounced measurements:
    Temp:      67.602
    Humidity:  46.835%
    Oxygen:    19.003%
    CO2 (ppm): 429.393
Average measurements:
    Temp:      67.568
    Humidity:  45.684%
    Oxygen:    19.631%
    CO2 (ppm): 423.498
Current intruders: 3
Calculated intruder risk: High

Megismerheti a kódot, és megtudhatja, hogyan működik az alkalmazás. A fő program futtatja a szimulációt. A lenyomás <Enter>után létrehoz egy helyiséget, és összegyűjt néhány kezdeti alapkonfigurációs adatot:

Console.WriteLine("Press <return> to start simulation");
Console.ReadLine();
var room = new Room("gallery");
var r = new Random();

int counter = 0;

room.TakeMeasurements(
    m =>
    {
        Console.WriteLine(room.Debounce);
        Console.WriteLine(room.Average);
        Console.WriteLine();
        counter++;
        return counter < 20000;
    });

Az alapadatok megállapítása után futtatja a szimulációt a helyiségben, ahol egy véletlenszerű számgenerátor megállapítja, hogy egy betolakodó lépett-e be a szobába:

counter = 0;
room.TakeMeasurements(
    m =>
    {
        Console.WriteLine(room.Debounce);
        Console.WriteLine(room.Average);
        room.Intruders += (room.Intruders, r.Next(5)) switch
        {
            ( > 0, 0) => -1,
            ( < 3, 1) => 1,
            _ => 0
        };

        Console.WriteLine($"Current intruders: {room.Intruders}");
        Console.WriteLine($"Calculated intruder risk: {room.RiskStatus}");
        Console.WriteLine();
        counter++;
        return counter < 200000;
    });

Más típusok tartalmazzák a méréseket, az utolsó 50 mérés átlagát és az összes elvégzett mérés átlagát.

Ezután futtassa az alkalmazást a .NET-objektumfoglalási eszközzel. Győződjön meg arról, hogy a buildet Release használja, nem a buildet Debug . A Hibakeresés menüben nyissa meg a Teljesítményprofilozót. Ellenőrizze a .NET-objektumfoglalás nyomon követését , de semmi mást. Futtassa az alkalmazást a befejezéshez. A profilkészítő méri az objektumfoglalásokat és a foglalásokról és a szemétgyűjtési ciklusokról szóló jelentéseket. Az alábbi ábrához hasonló gráfnak kell megjelennie:

Allocation graph for running the intruder alert app before any optimizations.

Az előző grafikonon látható, hogy a foglalások minimalizálása teljesítménybeli előnyökkel jár. Az élő objektumok gráfjában egy fűrészt ábrázoló minta látható. Ez azt jelzi, hogy számos objektum jön létre, amelyek gyorsan szemétté válnak. Ezeket később gyűjtjük össze, ahogy az objektum deltagráfjában is látható. A lefelé mutató piros sávok szemétgyűjtési ciklust jeleznek.

Ezután tekintse meg a gráfok alatti Foglalások lapot. Ez a táblázat azt mutatja be, hogy milyen típusok vannak a leginkább lefoglalva:

Chart that shows which types are allocated most frequently.

A System.String legtöbb foglalás típusfiókja. A legfontosabb feladat a sztringek lefoglalásának gyakoriságának minimalizálása. Ez az alkalmazás számos formázott kimenetet nyomtat folyamatosan a konzolra. Ebben a szimulációban meg szeretnénk tartani az üzeneteket, ezért a következő két sorra koncentrálunk: a SensorMeasurement típusra és a IntruderRisk típusra.

Kattintson duplán a SensorMeasurement vonalra. Láthatja, hogy az összes foglalás a static metódusban SensorMeasurement.TakeMeasurementtörténik. A metódust a következő kódrészletben tekintheti meg:

public static SensorMeasurement TakeMeasurement(string room, int intruders)
{
    return new SensorMeasurement
    {
        CO2 = (CO2Concentration + intruders * 10) + (20 * generator.NextDouble() - 10.0),
        O2 = (O2Concentration - intruders * 0.01) + (0.005 * generator.NextDouble() - 0.0025),
        Temperature = (TemperatureSetting + intruders * 0.05) + (0.5 * generator.NextDouble() - 0.25),
        Humidity = (HumiditySetting + intruders * 0.005) + (0.20 * generator.NextDouble() - 0.10),
        Room = room,
        TimeRecorded = DateTime.Now
    };
}

Minden mérés egy új SensorMeasurement objektumot foglal le, amely egy class típus. Minden SensorMeasurement létrehozott halomfoglalást okoz.

Osztályok átalakítása szerkezetekre

Az alábbi kód a következő kezdeti deklarációt SensorMeasurementmutatja:

public class SensorMeasurement
{
    private static readonly Random generator = new Random();

    public static SensorMeasurement TakeMeasurement(string room, int intruders)
    {
        return new SensorMeasurement
        {
            CO2 = (CO2Concentration + intruders * 10) + (20 * generator.NextDouble() - 10.0),
            O2 = (O2Concentration - intruders * 0.01) + (0.005 * generator.NextDouble() - 0.0025),
            Temperature = (TemperatureSetting + intruders * 0.05) + (0.5 * generator.NextDouble() - 0.25),
            Humidity = (HumiditySetting + intruders * 0.005) + (0.20 * generator.NextDouble() - 0.10),
            Room = room,
            TimeRecorded = DateTime.Now
        };
    }

    private const double CO2Concentration = 409.8; // increases with people.
    private const double O2Concentration = 0.2100; // decreases
    private const double TemperatureSetting = 67.5; // increases
    private const double HumiditySetting = 0.4500; // increases

    public required double CO2 { get; init; }
    public required double O2 { get; init; }
    public required double Temperature { get; init; }
    public required double Humidity { get; init; }
    public required string Room { get; init; }
    public required DateTime TimeRecorded { get; init; }

    public override string ToString() => $"""
            Room: {Room} at {TimeRecorded}:
                Temp:      {Temperature:F3}
                Humidity:  {Humidity:P3}
                Oxygen:    {O2:P3}
                CO2 (ppm): {CO2:F3}
            """;
}

A típus eredetileg azért lett létrehozva class , mert számos double mérést tartalmaz. Nagyobb, mint amennyit a gyakori elérési utakon szeretne másolni. Ez a döntés azonban sok kiosztást jelentett. Módosítsa a típust a class típusról a struct.

Az a-ról classstruct való váltás néhány fordítóhibát eredményez, mivel az eredeti kód hivatkozási ellenőrzéseket használt null néhány helyen. Az első az DebounceMeasurement osztályban van, a AddMeasurement metódusban:

public void AddMeasurement(SensorMeasurement datum)
{
    int index = totalMeasurements % debounceSize;
    recentMeasurements[index] = datum;
    totalMeasurements++;
    double sumCO2 = 0;
    double sumO2 = 0;
    double sumTemp = 0;
    double sumHumidity = 0;
    for (int i = 0; i < debounceSize; i++)
    {
        if (recentMeasurements[i] is not null)
        {
            sumCO2 += recentMeasurements[i].CO2;
            sumO2+= recentMeasurements[i].O2;
            sumTemp+= recentMeasurements[i].Temperature;
            sumHumidity += recentMeasurements[i].Humidity;
        }
    }
    O2 = sumO2 / ((totalMeasurements > debounceSize) ? debounceSize : totalMeasurements);
    CO2 = sumCO2 / ((totalMeasurements > debounceSize) ? debounceSize : totalMeasurements);
    Temperature = sumTemp / ((totalMeasurements > debounceSize) ? debounceSize : totalMeasurements);
    Humidity = sumHumidity / ((totalMeasurements > debounceSize) ? debounceSize : totalMeasurements);
}

A DebounceMeasurement típus 50 mérésből álló tömböt tartalmaz. Az érzékelő mérései az utolsó 50 mérés átlagaként jelennek meg. Ez csökkenti a zajt az értékekben. A teljes 50 érték leolvasása előtt ezek az értékek a következők null: . A kód a null rendszer indításakor a helyes átlag jelentéséhez keres hivatkozásokat. Miután módosította a SensorMeasurement típust egy szerkezetre, egy másik tesztet kell használnia. A SensorMeasurement típus tartalmaz egy string helyiségazonosítót, így ezt a tesztet használhatja:

if (recentMeasurements[i].Room is not null)

A másik három fordítóhiba mind abban a módszerben szerepel, amely ismétlődően végez méréseket egy helyiségben:

public void TakeMeasurements(Func<SensorMeasurement, bool> MeasurementHandler)
{
    SensorMeasurement? measure = default;
    do {
        measure = SensorMeasurement.TakeMeasurement(Name, Intruders);
        Average.AddMeasurement(measure);
        Debounce.AddMeasurement(measure);
    } while (MeasurementHandler(measure));
}

A kezdőmetódusban a helyi változó SensorMeasurementnull értékű hivatkozás:

SensorMeasurement? measure = default;

Most, hogy az SensorMeasurementstructclassérték nem egy, a null értékű érték egy null értékű típus. A deklarációt értéktípusra módosíthatja a fennmaradó fordítóhibák kijavításához:

SensorMeasurement measure = default;

Most, hogy a fordító hibáinak elhárítása megtörtént, meg kell vizsgálnia a kódot, hogy a szemantika ne változzon. Mivel struct a típusok érték szerint vannak átadva, a metódusparaméterek módosításai nem láthatók a metódus visszatérése után.

Fontos

Ha egy típust a típusról class a másikra struct módosít, az megváltoztathatja a program szemantikáját. Amikor egy típust class átadnak egy metódusnak, a metódusban végrehajtott összes mutáció az argumentumra kerül. Amikor egy típust struct átad egy metódusnak, és a metódusban végrehajtott mutációk az argumentum egy példányára kerülnek. Ez azt jelenti, hogy minden olyan metódust, amely az argumentumait terv szerint módosítja, frissíteni kell, hogy a ref módosító az a-ról a-ra class módosult bármely argumentumtípuson használható legyen struct.

A SensorMeasurement típus nem tartalmaz olyan metódusokat, amelyek módosítják az állapotot, ezért ez ebben a mintában nem okoz problémát. Ezt bizonyítja, ha hozzáadja a readonly módosítót a SensorMeasurement szerkezethez:

public readonly struct SensorMeasurement

A fordító kikényszeríti a readonly szerkezet természetét SensorMeasurement . Ha a kód ellenőrzése kihagyott egy módosított metódust, a fordító közli. Az alkalmazás továbbra is hibák nélkül épül fel, így ez a típus a következő readonly: . A módosító hozzáadása a readonly típusról class a típusra struct való váltáskor segíthet megtalálni azokat a tagokat, amelyek módosítják az structállapotot.

Kerülje a másolatkészítést

Számos szükségtelen foglalást eltávolított az alkalmazásból. A SensorMeasurement típus sehol nem jelenik meg a táblázatban.

Most még több munkát végez a SensorMeasurement struktúra másolásán minden alkalommal, amikor paraméterként vagy visszatérési értékként használják. A SensorMeasurement szerkezet négy dupla, egy DateTime és egy string. Ez a struktúra mérhetően nagyobb, mint egy hivatkozás. Vegyük fel a ref módosítókat az in olyan helyekre, ahol a SensorMeasurement típust használjuk.

A következő lépés a mérést visszaadó metódusok megkeresése, vagy a mérés argumentumként való használata, valamint a hivatkozások használata, ahol lehetséges. Kezdje a SensorMeasurement szerkezetben. A statikus TakeMeasurement metódus létrehoz és visszaad egy újat SensorMeasurement:

public static SensorMeasurement TakeMeasurement(string room, int intruders)
{
    return new SensorMeasurement
    {
        CO2 = (CO2Concentration + intruders * 10) + (20 * generator.NextDouble() - 10.0),
        O2 = (O2Concentration - intruders * 0.01) + (0.005 * generator.NextDouble() - 0.0025),
        Temperature = (TemperatureSetting + intruders * 0.05) + (0.5 * generator.NextDouble() - 0.25),
        Humidity = (HumiditySetting + intruders * 0.005) + (0.20 * generator.NextDouble() - 0.10),
        Room = room,
        TimeRecorded = DateTime.Now
    };
}

Ezt úgy fogjuk hagyni, ahogy van, érték szerint visszaadva. Ha megpróbál visszatérni ref, fordítóhiba jelenik meg. A metódusban helyileg létrehozott új struktúrába nem térhet vissza ref . A nem módosítható szerkezet kialakítása azt jelenti, hogy csak az építéskor állíthatja be a mérés értékeit. Ennek a módszernek létre kell hoznia egy új mérési szerkezetet.

Vizsgáljuk meg újra.DebounceMeasurement.AddMeasurement Adja hozzá a in módosítót a measurement paraméterhez:

public void AddMeasurement(in SensorMeasurement datum)
{
    int index = totalMeasurements % debounceSize;
    recentMeasurements[index] = datum;
    totalMeasurements++;
    double sumCO2 = 0;
    double sumO2 = 0;
    double sumTemp = 0;
    double sumHumidity = 0;
    for (int i = 0; i < debounceSize; i++)
    {
        if (recentMeasurements[i].Room is not null)
        {
            sumCO2 += recentMeasurements[i].CO2;
            sumO2+= recentMeasurements[i].O2;
            sumTemp+= recentMeasurements[i].Temperature;
            sumHumidity += recentMeasurements[i].Humidity;
        }
    }
    O2 = sumO2 / ((totalMeasurements > debounceSize) ? debounceSize : totalMeasurements);
    CO2 = sumCO2 / ((totalMeasurements > debounceSize) ? debounceSize : totalMeasurements);
    Temperature = sumTemp / ((totalMeasurements > debounceSize) ? debounceSize : totalMeasurements);
    Humidity = sumHumidity / ((totalMeasurements > debounceSize) ? debounceSize : totalMeasurements);
}

Ez egy másolási műveletet ment. A in paraméter a hívó által már létrehozott másolatra mutató hivatkozás. A példányt a típus metódusával TakeMeasurementRoom is mentheti. Ez a módszer bemutatja, hogy a fordító hogyan biztosítja a biztonságot, ha argumentumokat refad át. A típus kezdeti TakeMeasurement metódusa a Room következő argumentumot Func<SensorMeasurement, bool>veszi fel: . Ha megpróbálja hozzáadni a vagy ref módosítót a in deklarációhoz, a fordító hibát jelez. Nem adhat át argumentumot ref lambdakifejezésnek. A fordító nem tudja garantálni, hogy a hívott kifejezés nem másolja a hivatkozást. Ha a lambda kifejezés rögzíti a hivatkozást, a hivatkozás élettartama hosszabb lehet, mint a hivatkozott érték. Ha a ref biztonságos környezetén kívülre fér hozzá, memóriasérülést okozna. A ref biztonsági szabályok nem teszik lehetővé. A ref biztonsági funkcióinak áttekintésében többet is megtudhat.

Szemantikák megőrzése

A végleges módosításkészletek nem befolyásolják nagy mértékben az alkalmazás teljesítményét, mert a típusok nem gyakori elérésű útvonalakon jönnek létre. Ezek a módosítások a teljesítményhangolásban használt egyéb technikák némelyikét szemléltetik. Tekintsük meg a kezdeti Room osztályt:

public class Room
{
    public AverageMeasurement Average { get; } = new ();
    public DebounceMeasurement Debounce { get; } = new ();
    public string Name { get; }

    public IntruderRisk RiskStatus
    {
        get
        {
            var CO2Variance = (Debounce.CO2 - Average.CO2) > 10.0 / 4;
            var O2Variance = (Average.O2 - Debounce.O2) > 0.005 / 4.0;
            var TempVariance = (Debounce.Temperature - Average.Temperature) > 0.05 / 4.0;
            var HumidityVariance = (Debounce.Humidity - Average.Humidity) > 0.20 / 4;
            IntruderRisk risk = IntruderRisk.None;
            if (CO2Variance) { risk++; }
            if (O2Variance) { risk++; }
            if (TempVariance) { risk++; }
            if (HumidityVariance) { risk++; }
            return risk;
        }
    }

    public int Intruders { get; set; }

    
    public Room(string name)
    {
        Name = name;
    }

    public void TakeMeasurements(Func<SensorMeasurement, bool> MeasurementHandler)
    {
        SensorMeasurement? measure = default;
        do {
            measure = SensorMeasurement.TakeMeasurement(Name, Intruders);
            Average.AddMeasurement(measure);
            Debounce.AddMeasurement(measure);
        } while (MeasurementHandler(measure));
    }
}

Ez a típus több tulajdonságot is tartalmaz. Néhány típus class . Egy Room objektum létrehozása több foglalást is magában foglal. Egyet önmagáért Room , egyet pedig egy-egy class a benne található típus minden egyes tagjára. A tulajdonságok közül kettő típusról class típusra struct alakítható át: a típusokra és AverageMeasurement a DebounceMeasurement típusokra. Vizsgáljuk meg ezt az átalakítást mindkét típussal.

Módosítsa a típust DebounceMeasurement a következőrestruct: aclass. Ez egy fordítóhibát CS8983: A 'struct' with field initializers must include an explicitly declared constructoreredményez. Ezt egy üres paraméter nélküli konstruktor hozzáadásával javíthatja:

public DebounceMeasurement() { }

Erről a követelményről a szerkezetekről szóló nyelvi referenciacikkben tudhat meg többet.

A Object.ToString() felülbírálás nem módosítja a szerkezet egyik értékét sem. A módosító hozzáadható a readonly metódusdeklarációhoz. A DebounceMeasurement típus nem módosítható, ezért gondoskodnia kell arról, hogy a módosítások ne befolyásolják az elvetett másolatokat. A AddMeasurement metódus módosítja az objektum állapotát. A metódus az Room osztályból van meghívva TakeMeasurements . A metódus meghívása után is meg szeretné őrizni ezeket a módosításokat. A tulajdonságot módosíthatja úgyRoom.Debounce, hogy a típus egyetlen példányára DebounceMeasurement mutató hivatkozást adjon vissza:

private DebounceMeasurement debounce = new();
public ref readonly DebounceMeasurement Debounce { get { return ref debounce; } }

Az előző példában van néhány változás. Először is a tulajdonság egy olvasható tulajdonság, amely a helyiség tulajdonában lévő példányra mutató, olvasható hivatkozást ad vissza. Most már egy deklarált mező is alátámasztja, amely inicializálva van az Room objektum példányosításakor. A módosítások elvégzése után frissíteni fogja a metódus implementálását AddMeasurement . A privát háttérmezőt használja, debouncenem az olvasható tulajdonságot Debounce. Így a módosítások az inicializálás során létrehozott egyetlen példányon történnek.

Ugyanez a technika működik a Average tulajdonsággal. Először módosítsa a típust egyről AverageMeasurement egyre classstruct, majd adja hozzá a readonly módosítót a ToString metódushoz:

namespace IntruderAlert;

public struct AverageMeasurement
{
    private double sumCO2 = 0;
    private double sumO2 = 0;
    private double sumTemperature = 0;
    private double sumHumidity = 0;
    private int totalMeasurements = 0;

    public AverageMeasurement() { }

    public readonly double CO2 => sumCO2 / totalMeasurements;
    public readonly double O2 => sumO2 / totalMeasurements;
    public readonly double Temperature => sumTemperature / totalMeasurements;
    public readonly double Humidity => sumHumidity / totalMeasurements;

    public void AddMeasurement(in SensorMeasurement datum)
    {
        totalMeasurements++;
        sumCO2 += datum.CO2;
        sumO2 += datum.O2;
        sumTemperature += datum.Temperature;
        sumHumidity+= datum.Humidity;
    }

    public readonly override string ToString() => $"""
        Average measurements:
            Temp:      {Temperature:F3}
            Humidity:  {Humidity:P3}
            Oxygen:    {O2:P3}
            CO2 (ppm): {CO2:F3}
        """;
}

Ezután a Room tulajdonsághoz használt technikát követve módosítja az osztályt Debounce . A Average tulajdonság egy értéket ad vissza readonly ref a magánmezőbe az átlagos méréshez. A AddMeasurement metódus módosítja a belső mezőket.

private AverageMeasurement average = new();
public  ref readonly AverageMeasurement Average { get { return ref average; } }

Kerülje a boxolást

A teljesítmény javítása érdekében van még egy utolsó változás. A fő program a szoba statisztikáinak nyomtatása, beleértve a kockázatértékelést:

Console.WriteLine($"Current intruders: {room.Intruders}");
Console.WriteLine($"Calculated intruder risk: {room.RiskStatus}");

A generált ToString hívás az enumerálás értékét adja meg. Ezt elkerülheti, ha felülbírálást ír az Room osztályba, amely a becsült kockázat értéke alapján formázza a sztringet:

public override string ToString() =>
    $"Calculated intruder risk: {RiskStatus switch
    {
        IntruderRisk.None => "None",
        IntruderRisk.Low => "Low",
        IntruderRisk.Medium => "Medium",
        IntruderRisk.High => "High",
        IntruderRisk.Extreme => "Extreme",
        _ => "Error!"
    }}, Current intruders: {Intruders.ToString()}";

Ezután módosítsa a kódot a fő programban az új ToString metódus meghívásához:

Console.WriteLine(room.ToString());

Futtassa az alkalmazást a profilkészítővel, és tekintse meg a foglalások frissített tábláját.

Allocation graph for running the intruder alert app after modifications.

Számos foglalást eltávolított, és teljesítménynövelő funkciót biztosított az alkalmazásnak.

Ref-biztonság használata az alkalmazásban

Ezek a technikák alacsony szintű teljesítményhangolást jelentenek. Növelhetik az alkalmazás teljesítményét a gyakori elérésű útvonalakra alkalmazva, valamint a módosítások előtti és utáni hatás mérésére. A legtöbb esetben a következő ciklust fogja követni:

  • Mértékfoglalások: Határozza meg, hogy mely típusok vannak a leginkább lefoglalva, és mikor lehet csökkenteni a halomfoglalásokat.
  • Osztály átalakítása strukturálttá: A típusok sokszor átalakíthatók egy class osztályból egybe struct. Az alkalmazás veremterületet használ a halomfoglalások helyett.
  • Szemantikák megőrzése: Az a classstruct paraméter átalakítása hatással lehet a paraméterek szemantikára, és visszaadhatja az értékeket. Minden olyan metódusnak, amely módosítja a paramétereit, most már meg kell jelölnie ezeket a paramétereket a ref módosítóval. Ez biztosítja, hogy a módosítások a megfelelő objektumon legyenek elvégezve. Hasonlóképpen, ha a hívónak módosítania kell egy tulajdonság vagy metódus visszatérési értékét, a visszatérést a ref módosítóval kell megjelölni.
  • Kerülje a másolást: Ha egy nagy szerkezetet ad át paraméterként, a módosítóval megjelölheti a in paramétert. Kevesebb bájtban adhat át egy hivatkozást, és győződjön meg arról, hogy a metódus nem módosítja az eredeti értéket. Az értékeket readonly ref úgy is visszaadhatja, hogy olyan hivatkozást ad vissza, amely nem módosítható.

Ezekkel a technikákkal javíthatja a teljesítményt a kód gyakori elérési útjaiban.