Delen via


Zelfstudie: Geheugentoewijzingen verminderen met ref veiligheid

Vaak bestaat het afstemmen van prestaties voor een .NET-toepassing uit twee technieken. Verminder eerst het aantal en de grootte van heap-toewijzingen. Ten tweede vermindert u hoe vaak gegevens worden gekopieerd. Visual Studio biedt geweldige hulpprogramma's waarmee u kunt analyseren hoe uw toepassing geheugen gebruikt. Zodra u hebt vastgesteld waar uw app onnodige toewijzingen aanbrengt, brengt u wijzigingen aan om deze toewijzingen te minimaliseren. U converteert class typen naar struct typen. U gebruikt ref veiligheidsfunctiesom semantiek te behouden en extra kopiëren te minimaliseren.

Gebruik Visual Studio 17.5 voor de beste ervaring met deze zelfstudie. Het hulpprogramma voor het toewijzen van .NET-objecten dat wordt gebruikt voor het analyseren van geheugengebruik maakt deel uit van Visual Studio. U kunt Visual Studio Code en de opdrachtregel gebruiken om de toepassing uit te voeren en alle wijzigingen aan te brengen. U kunt de analyseresultaten van uw wijzigingen echter niet zien.

De toepassing die u gaat gebruiken, is een simulatie van een IoT-toepassing die verschillende sensoren bewaakt om te bepalen of een indringer een geheime galerie met waardevolle gegevens heeft ingevoerd. De IoT-sensoren verzenden voortdurend gegevens die de combinatie van Zuurstof (O2) en Koolstofdioxide (CO2) in de lucht meten. Ze rapporteren ook de temperatuur en relatieve vochtigheid. Elk van deze waarden fluctueert de hele tijd enigszins. Wanneer een persoon echter de kamer binnenkomt, verandert de verandering iets meer en altijd in dezelfde richting: Zuurstof neemt af, koolstofdioxide neemt toe, temperatuur neemt toe, net als relatieve vochtigheid. Wanneer de sensoren worden gecombineerd om toenamen weer te geven, wordt het indringeralarm geactiveerd.

In deze zelfstudie voert u de toepassing uit, voert u metingen uit op geheugentoewijzingen en verbetert u de prestaties door het aantal toewijzingen te verminderen. De broncode is beschikbaar in de voorbeeldbrowser.

De starterstoepassing verkennen

Download de toepassing en voer het startersvoorbeeld uit. De starterstoepassing werkt correct, maar omdat er veel kleine objecten met elke meetcyclus worden toegewezen, verslechtert de prestaties langzaam terwijl deze in de loop van de tijd wordt uitgevoerd.

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

Veel rijen zijn verwijderd.

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

U kunt de code verkennen om te leren hoe de toepassing werkt. Het hoofdprogramma voert de simulatie uit. Nadat u op de knop drukt <Enter>, wordt er een ruimte gemaakt en worden enkele initiële basislijngegevens verzameld:

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;
    });

Zodra die basislijngegevens zijn vastgesteld, wordt de simulatie uitgevoerd op de ruimte, waarbij een generator voor willekeurige getallen bepaalt of een indringer de ruimte heeft ingevoerd:

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;
    });

Andere typen bevatten de metingen, een gedebouncede meting die het gemiddelde is van de laatste 50 metingen en het gemiddelde van alle genomen metingen.

Voer vervolgens de toepassing uit met behulp van het hulpprogramma .NET-objecttoewijzing. Zorg ervoor dat u de Release build gebruikt, niet de Debug build. Open in het menu Foutopsporing de performance profiler. Controleer de optie voor het bijhouden van .NET-objecten, maar niets anders. Voer uw toepassing uit om deze te voltooien. De profiler meet objecttoewijzingen en -rapporten over toewijzingen en garbagecollectioncycli. Als het goed is, ziet u een grafiek die lijkt op de volgende afbeelding:

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

In de vorige grafiek ziet u dat het werken om toewijzingen te minimaliseren prestatievoordelen biedt. U ziet een zaagtandpatroon in de grafiek met liveobjecten. Dat vertelt u dat er talloze objecten worden gemaakt die snel afval worden. Ze worden later verzameld, zoals wordt weergegeven in de object deltagrafiek. De omlaag rode balken geven een garbagecollectioncyclus aan.

Bekijk vervolgens het tabblad Toewijzingen onder de grafieken. In deze tabel ziet u welke typen het meest worden toegewezen:

Chart that shows which types are allocated most frequently.

Het System.String type accounts voor de meeste toewijzingen. De belangrijkste taak moet zijn om de frequentie van tekenreekstoewijzingen te minimaliseren. Deze toepassing drukt voortdurend talloze opgemaakte uitvoer af op de console. Voor deze simulatie willen we berichten bewaren, dus concentreren we ons op de volgende twee rijen: het SensorMeasurement type en het IntruderRisk type.

Dubbelklik op de SensorMeasurement regel. U kunt zien dat alle toewijzingen plaatsvinden in de static methode SensorMeasurement.TakeMeasurement. U kunt de methode in het volgende codefragment zien:

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
    };
}

Elke meting wijst een nieuw SensorMeasurement object toe, een class type. Elke SensorMeasurement gemaakte oorzaak is een heap-toewijzing.

Klassen wijzigen in structs

De volgende code toont de eerste declaratie van SensorMeasurement:

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}
            """;
}

Het type is oorspronkelijk gemaakt als een class omdat het talloze double metingen bevat. Het is groter dan u wilt kopiëren in dynamische paden. Deze beslissing betekende echter een groot aantal toewijzingen. Wijzig het type van een class in een struct.

Als u overstapt van een class naar een aantal struct compilerfouten, worden er enkele compilerfouten geïntroduceerd omdat de oorspronkelijke code referentiecontroles op een paar plekken heeft gebruikt null . De eerste bevindt zich in de DebounceMeasurement klasse, in de AddMeasurement methode:

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);
}

Het DebounceMeasurement type bevat een matrix van 50 metingen. De metingen voor een sensor worden gerapporteerd als het gemiddelde van de laatste 50 metingen. Dat vermindert het geluid in de metingen. Voordat een volledige 50 metingen zijn genomen, zijn nulldeze waarden. De code controleert op null verwijzing om het juiste gemiddelde te rapporteren bij het opstarten van het systeem. Nadat u het SensorMeasurement type hebt gewijzigd in een struct, moet u een andere test gebruiken. Het SensorMeasurement type bevat een string voor de ruimte-id, zodat u deze test kunt gebruiken:

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

De andere drie compilerfouten zijn allemaal aanwezig in de methode die herhaaldelijk metingen in een ruimte neemt:

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));
}

In de startersmethode is de lokale variabele voor de SensorMeasurement variabele een null-verwijzing:

SensorMeasurement? measure = default;

Nu het SensorMeasurement een struct in plaats van een classis, is het nullable een type null-waarde. U kunt de declaratie wijzigen in een waardetype om de resterende compilerfouten op te lossen:

SensorMeasurement measure = default;

Nu de compilerfouten zijn opgelost, moet u de code onderzoeken om ervoor te zorgen dat de semantiek niet is gewijzigd. Omdat struct typen worden doorgegeven door waarde, zijn wijzigingen in methodeparameters niet zichtbaar nadat de methode is geretourneerd.

Belangrijk

Als u een type wijzigt van een in een classstruct , kunt u de semantiek van uw programma wijzigen. Wanneer een class type wordt doorgegeven aan een methode, worden alle mutaties die in de methode zijn gemaakt, aan het argument toegevoegd. Wanneer een struct type wordt doorgegeven aan een methode en mutaties die in de methode zijn gemaakt, worden gemaakt in een kopie van het argument. Dit betekent dat elke methode die de argumenten ontwerpt, moet worden bijgewerkt om de ref wijzigingsfunctie te gebruiken voor elk argumenttype dat u hebt gewijzigd van een class in een struct.

Het SensorMeasurement type bevat geen methoden die de status wijzigen, dus dat is geen probleem in dit voorbeeld. U kunt dat bewijzen door de readonly modifier toe te voegen aan de SensorMeasurement struct:

public readonly struct SensorMeasurement

De compiler dwingt de readonly aard van de SensorMeasurement struct af. Als uw inspectie van de code een methode mist die de status heeft gewijzigd, zou de compiler u dit vertellen. Uw app bouwt nog steeds zonder fouten, dus dit type is readonly. Door de readonly wijzigingsfunctie toe te voegen wanneer u een type wijzigt van een class in een struct , kunt u leden vinden die de status van de struct.

Vermijd het maken van kopieën

U hebt een groot aantal onnodige toewijzingen uit uw app verwijderd. Het SensorMeasurement type wordt nergens in de tabel weergegeven.

Nu gaat het extra werk doen om de SensorMeasurement structuur te kopiëren telkens wanneer deze wordt gebruikt als parameter of een retourwaarde. De SensorMeasurement struct bevat vier doubles, a DateTime en a string. Die structuur is aanzienlijk groter dan een verwijzing. Laten we de ref of in modifiers toevoegen aan plaatsen waar het SensorMeasurement type wordt gebruikt.

De volgende stap is het vinden van methoden die een meting retourneren of een meting als argument uitvoeren en waar mogelijk verwijzingen gebruiken. Begin in de SensorMeasurement struct. De statische TakeMeasurement methode maakt en retourneert een nieuw 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
    };
}

We laten deze als zodanig achter en retourneren per waarde. Als u probeert terug te keren door ref, krijgt u een compilerfout. U kunt geen lokale structuur retourneren ref naar een nieuwe structuur die in de methode is gemaakt. Het ontwerp van de onveranderbare struct betekent dat u alleen de waarden van de meting bij de bouw kunt instellen. Deze methode moet een nieuwe meetstruct maken.

Laten we eens kijken DebounceMeasurement.AddMeasurementnaar . U moet de in wijzigingsfunctie toevoegen aan de measurement parameter:

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);
}

Hiermee wordt één kopieerbewerking opgeslagen. De in parameter is een verwijzing naar de kopie die al door de aanroeper is gemaakt. U kunt ook een kopie opslaan met de TakeMeasurement methode in het Room type. Deze methode illustreert hoe de compiler veiligheid biedt wanneer u argumenten doorgeeft ref. De eerste TakeMeasurement methode in het Room type neemt een argument van Func<SensorMeasurement, bool>. Als u de in of ref wijzigingsfunctie aan die declaratie probeert toe te voegen, meldt de compiler een fout. U kunt geen ref argument doorgeven aan een lambda-expressie. De compiler kan niet garanderen dat de aangeroepen expressie de verwijzing niet kopieert. Als de lambda-expressie de verwijzing vastlegt , kan de verwijzing een levensduur hebben die langer duurt dan de waarde waarnaar wordt verwezen. Toegang tot deze buiten de veilige context van de ref zou leiden tot beschadiging van het geheugen. De ref veiligheidsregels staan het niet toe. Meer informatie vindt u in het overzicht van refveiligheidsfuncties.

Semantiek behouden

De laatste sets wijzigingen hebben geen grote invloed op de prestaties van deze toepassing, omdat de typen niet in dynamische paden worden gemaakt. Deze wijzigingen illustreren enkele van de andere technieken die u zou gebruiken bij het afstemmen van de prestaties. Laten we eens kijken naar de eerste Room klas:

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));
    }
}

Dit type bevat verschillende eigenschappen. Sommige zijn class typen. Het maken van een Room object omvat meerdere toewijzingen. Eén voor zichzelf Room en één voor elk van de leden van een class type dat het bevat. U kunt twee van deze eigenschappen converteren van class typen naar struct typen: de DebounceMeasurement en AverageMeasurement typen. Laten we die transformatie met beide typen doorlopen.

Wijzig het DebounceMeasurement type van een class in struct. Hiermee wordt een compilerfout CS8983: A 'struct' with field initializers must include an explicitly declared constructorgeïntroduceerd. U kunt dit oplossen door een lege parameterloze constructor toe te voegen:

public DebounceMeasurement() { }

Meer informatie over deze vereiste vindt u in het naslagartikel over taalinformatie over structs.

De Object.ToString() onderdrukking wijzigt geen van de waarden van de struct. U kunt de readonly wijzigingsfunctie toevoegen aan die methodedeclaratie. Het DebounceMeasurement type kan worden gedempt, dus u moet ervoor zorgen dat wijzigingen geen invloed hebben op kopieën die worden verwijderd. De AddMeasurement methode wijzigt de status van het object. Het wordt aangeroepen vanuit de Room klasse, in de TakeMeasurements methode. U wilt dat deze wijzigingen behouden blijven nadat u de methode hebt aangeroepen. U kunt de Room.Debounce eigenschap wijzigen om een verwijzing naar één exemplaar van het DebounceMeasurement type te retourneren:

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

In het vorige voorbeeld zijn enkele wijzigingen aangebracht. Ten eerste is de eigenschap een alleen-lezen eigenschap die een alleen-lezen verwijzing retourneert naar het exemplaar dat eigendom is van deze ruimte. Het wordt nu ondersteund door een gedeclareerd veld dat wordt geïnitialiseerd wanneer het Room object wordt geïnstantieerd. Nadat u deze wijzigingen hebt aangebracht, werkt u de implementatie van AddMeasurement de methode bij. Het maakt gebruik van het privé-backingveld, debounceniet de alleen-lezen eigenschap Debounce. Op die manier vinden de wijzigingen plaats op het enkele exemplaar dat tijdens de initialisatie is gemaakt.

Dezelfde techniek werkt met de Average eigenschap. Eerst wijzigt u het AverageMeasurement type van een class in een structen voegt u de readonly wijzigingsfunctie toe aan de ToString methode:

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}
        """;
}

Vervolgens wijzigt u de Room klasse volgens dezelfde techniek die u voor de Debounce eigenschap hebt gebruikt. De Average eigenschap retourneert een readonly ref naar het privéveld voor de gemiddelde meting. De AddMeasurement methode wijzigt de interne velden.

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

Voorkom boksen

Er is één laatste wijziging om de prestaties te verbeteren. Het belangrijkste programma is het afdrukken van statistieken voor de ruimte, met inbegrip van de risicoanalyse:

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

De aanroep naar de gegenereerde ToString vakken de opsommingswaarde. U kunt dit voorkomen door een onderdrukking te schrijven in de Room klasse waarmee de tekenreeks wordt opgemaakt op basis van de waarde van het geschatte risico:

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()}";

Wijzig vervolgens de code in het hoofdprogramma om deze nieuwe ToString methode aan te roepen:

Console.WriteLine(room.ToString());

Voer de app uit met behulp van de profiler en bekijk de bijgewerkte tabel voor toewijzingen.

Allocation graph for running the intruder alert app after modifications.

U hebt talloze toewijzingen verwijderd en uw app voorzien van een prestatieverbeteringen.

Ref-veiligheid gebruiken in uw toepassing

Deze technieken zijn het afstemmen van prestaties op laag niveau. Ze kunnen de prestaties in uw toepassing verbeteren wanneer ze worden toegepast op dynamische paden en wanneer u de impact voor en na de wijzigingen hebt gemeten. In de meeste gevallen is de cyclus die u volgt:

  • Toewijzingen van metingen: bepaal welke typen het meest worden toegewezen en wanneer u de heap-toewijzingen kunt verminderen.
  • Klasse converteren naar struct: Vaak kunnen typen worden geconverteerd van een class naar een struct. Uw app maakt gebruik van stackruimte in plaats van heap-toewijzingen te maken.
  • Semantiek behouden: het converteren van een class naar een struct kan van invloed zijn op de semantiek voor parameters en retourwaarden. Elke methode die de parameters wijzigt, moet deze parameters nu markeren met de ref wijzigingsfunctie. Dit zorgt ervoor dat de wijzigingen aan het juiste object worden aangebracht. Als een eigenschap of methode-retourwaarde door de aanroeper moet worden gewijzigd, moet die return worden gemarkeerd met de ref wijzigingsfunctie.
  • Vermijd kopieën: wanneer u een grote struct als parameter doorgeeft, kunt u de parameter markeren met de in wijzigingsfunctie. U kunt een verwijzing doorgeven in minder bytes en ervoor zorgen dat de methode de oorspronkelijke waarde niet wijzigt. U kunt ook waarden retourneren door readonly ref een verwijzing te retourneren die niet kan worden gewijzigd.

Met deze technieken kunt u de prestaties in dynamische paden van uw code verbeteren.