Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Belangrijk
De technieken die in deze sectie worden beschreven, verbeteren de prestaties wanneer ze worden toegepast op dynamische paden in uw code. Dynamische paden zijn de secties van uw codebasis die vaak en herhaaldelijk worden uitgevoerd in normale bewerkingen. Het toepassen van deze technieken op code die niet vaak wordt uitgevoerd, heeft minimale gevolgen. Voordat u wijzigingen aanbrengt om de prestaties te verbeteren, is het essentieel om een basislijn te meten. Analyseer vervolgens die basislijn om te bepalen waar knelpunten in het geheugen optreden. U vindt meer informatie over veel platformoverschrijdende hulpprogramma's om de prestaties van uw toepassing te meten in de sectie diagnostische gegevens en instrumentatie. In de zelfstudie kunt u oefenen met een profileringssessie om het geheugengebruik te meten in de Visual Studio-documentatie.
Zodra u het geheugengebruik hebt gemeten en hebt vastgesteld dat u toewijzingen kunt verminderen, gebruikt u de technieken in deze sectie om toewijzingen te verminderen. Na elke opeenvolgende wijziging meet u het geheugengebruik opnieuw. Zorg ervoor dat elke wijziging een positieve invloed heeft op het geheugengebruik in uw toepassing.
Prestatiewerkzaamheden in .NET betekenen vaak dat toewijzingen uit uw code worden verwijderd. Elk geheugenblok dat u toewijst, moet uiteindelijk worden vrijgemaakt. Minder toewijzingen verminderen de tijd die wordt besteed aan het verzamelen van afval. Het maakt een voorspelbare uitvoeringstijd mogelijk door garbage collections uit specifieke codepaden te verwijderen.
Een veelvoorkomende tactiek voor het verminderen van toewijzingen is het wijzigen van kritieke gegevensstructuren van class typen in struct typen. Deze wijziging heeft invloed op de semantiek van het gebruik van deze typen. Parameters en resultaten worden nu door waarde doorgegeven in plaats van per verwijzing. De kosten voor het kopiëren van een waarde zijn te verwaarlozen als de typen klein zijn, drie woorden of minder, waarbij wordt uitgegaan van een woord dat de natuurlijke grootte heeft van een geheel getal. Het is meetbaar en kan echte invloed hebben op de prestaties voor grotere typen. Om het effect van kopiëren te bestrijden, kunnen ontwikkelaars deze typen ref doorgeven om de beoogde semantiek terug te krijgen.
De C# ref -functies bieden u de mogelijkheid om de gewenste semantiek voor struct typen uit te drukken zonder de algehele bruikbaarheid te beïnvloeden. Vóór deze verbeteringen moesten ontwikkelaars zich richten op unsafe constructies met aanwijzers en onbewerkt geheugen om dezelfde invloed op de prestaties te bereiken. De compiler genereert verifieerbare veilige code voor de nieuwe ref gerelateerde functies.
Verifieerbare veilige code betekent dat de compiler mogelijke bufferoverschrijdingen detecteert of toegang heeft tot niet-toegewezen of vrijgemaakt geheugen. De compiler detecteert en voorkomt enkele fouten.
Doorgeven en teruggeven via verwijzing
Variabelen in C# slaan waarden op. In struct typen is de waarde de inhoud van een instantie van het type. In class typen is de waarde een verwijzing naar een blok geheugen waarin een exemplaar van het type wordt opgeslagen. Als u de ref wijzigingsfunctie toevoegt, betekent dit dat de variabele de verwijzing naar de waarde opslaat. In struct typen wijst de referentie naar de opslag die de waarde bevat. In class typen wijst de referentie naar de opslag die de referentie naar het geheugenblok bevat.
In C# worden parameters aan methoden doorgegeven door waarde en retourwaarden worden geretourneerd op waarde. De waarde van het argument wordt doorgegeven aan de methode. De waarde van het retourargument is de retourwaarde.
De ref, in, ref readonly of out modifier geeft aan dat het argument door verwijzing wordt doorgegeven. Er wordt een verwijzing naar de opslaglocatie doorgegeven aan de methode. Toevoegen ref aan de methodehandtekening betekent dat de retourwaarde wordt geretourneerd door verwijzing. Een verwijzing naar de opslaglocatie is de retourwaarde.
U kunt verw-toewijzing ook gebruiken om een variabele te laten verwijzen naar een andere variabele. Een typische toewijzing kopieert de waarde van de rechterkant naar de variabele aan de linkerkant van de toewijzing. Een verw-toewijzing kopieert de geheugenlocatie van de variabele aan de rechterkant naar de variabele aan de linkerkant. De ref oorspronkelijke variabele verwijst nu naar:
int anInteger = 42; // assignment.
ref int location = ref anInteger; // ref assignment.
ref int sameLocation = ref location; // ref assignment
Console.WriteLine(location); // output: 42
sameLocation = 19; // assignment
Console.WriteLine(anInteger); // output: 19
Wanneer u een variabele toewijst , wijzigt u de waarde ervan. Wanneer u een variabele toewijst , wijzigt u waarnaar deze verwijst.
U kunt rechtstreeks werken met de opslag voor waarden met behulp van ref variabelen, passeren door reference en ref-toewijzing. Bereikregels die door de compiler worden afgedwongen, zorgen voor veiligheid bij het rechtstreeks werken met opslag.
De ref readonly en in modifiers geven zowel aan dat het argument met een referentie moet worden doorgegeven, en niet opnieuw toegewezen kan worden binnen de methode. Het verschil is dat ref readonly aangeeft dat de methode de parameter als variabele gebruikt. De methode kan de parameter vastleggen, of de parameter kan worden geretourneerd via een alleen-lezen referentie. In die gevallen moet u de ref readonly modifier gebruiken. Anders biedt de in wijzigingsfunctie meer flexibiliteit. U hoeft de in wijzigingsfunctie niet toe te voegen aan een argument voor een in parameter, zodat u bestaande API-handtekeningen veilig kunt bijwerken met behulp van de in wijzigingsfunctie. De compiler geeft een waarschuwing als u of de ref of de in modifier niet toevoegt aan een argument voor een ref readonly parameter.
Veilige context voor referentie
C# bevat regels voor ref expressies om ervoor te zorgen dat een ref expressie niet kan worden geopend waar de opslag waarnaar wordt verwezen, niet langer geldig is. Bekijk het volgende voorbeeld:
public ref int CantEscape()
{
int index = 42;
return ref index; // Error: index's ref safe context is the body of CantEscape
}
De compiler rapporteert een fout omdat u vanuit een methode geen verwijzing naar een lokale variabele kunt retourneren. De aanroeper heeft geen toegang tot de opslag waarnaar wordt verwezen. De context voor ref safe definieert het bereik waarin een ref expressie veilig is voor toegang of wijziging. De volgende tabel bevat de veilige contexten voor ref voor variabele typen.
ref velden kunnen niet worden gedefinieerd in een class of niet-referentie struct, waardoor deze rijen zich niet in de tabel bevinden.
| Verklaring | ref safe context |
|---|---|
| niet-verwijzingslokaal | het blok waarin de variabele 'local' wordt gedeclareerd |
| niet-referentieparameter | huidige methode |
ref, parameter ref readonlyin |
aanroepmethode |
out parameter |
huidige methode |
class veld |
aanroepmethode |
niet-verwijzingsveld struct |
huidige methode |
ref veld van ref struct |
aanroepmethode |
Een variabele kan worden ref geretourneerd als de ref veilige context de aanroepmethode is. Als de veilige context van de ref de huidige methode of een blok is, ref is return niet toegestaan. In het volgende codefragment ziet u twee voorbeelden. Een lidveld kan worden geopend vanuit het bereik dat een methode aanroept, dus de veilige context van een klasse- of structveld is de aanroepmethode. De ref-veilige context voor een parameter met de ref of in modifiers is de hele methode. Beide kunnen worden ref geretourneerd vanuit een lidmethode:
private int anIndex;
public ref int RetrieveIndexRef()
{
return ref anIndex;
}
public ref int RefMin(ref int left, ref int right)
{
if (left < right)
return ref left;
else
return ref right;
}
Opmerking
Wanneer de ref readonly of in modifier wordt toegepast op een parameter, kan die parameter worden geretourneerd door ref readonly, niet ref.
De compiler zorgt ervoor dat een verwijzing niet kan ontsnappen aan de veilige context van de ref. U kunt ref parameters, ref return, en ref lokale variabelen veilig gebruiken omdat de compiler detecteert of u per ongeluk code hebt geschreven waarin een ref uitdrukking kan worden geopend wanneer de opslag niet geldig is.
Veilige context en referentiestructuren
ref struct voor typen zijn meer regels vereist om ervoor te zorgen dat ze veilig kunnen worden gebruikt. Een ref struct type kan velden bevatten ref . Hiervoor is een veilige context vereist. Voor de meeste typen is de veilige context de aanroepmethode. Met andere woorden, een waarde die niet een ref struct waarde is, kan altijd worden geretourneerd vanuit een methode.
Informeel is de veilige context voor een ref struct de scope waar alle ref velden toegankelijk zijn. Met andere woorden, het is het kruispunt van de referentieve veilige context van al zijn ref velden. De volgende methode retourneert een ReadOnlySpan<char> naar een lidveld, waardoor de veilige context de methode is.
private string longMessage = "This is a long message";
public ReadOnlySpan<char> Safe()
{
var span = longMessage.AsSpan();
return span;
}
De volgende code verzendt daarentegen een fout omdat het ref field lid van de Span<int> code verwijst naar de toegewezen stackmatrix met gehele getallen. Er is geen ontsnappen aan de methode
public Span<int> M()
{
int length = 3;
Span<int> numbers = stackalloc int[length];
for (var i = 0; i < length; i++)
{
numbers[i] = i;
}
return numbers; // Error! numbers can't escape this method.
}
Geheugentypen samenvoegen
De introductie van System.Span<T> en System.Memory<T> biedt een geïntegreerd model voor het werken met geheugen.
System.ReadOnlySpan<T> en System.ReadOnlyMemory<T> bieden leesversies voor toegang tot geheugen. Ze bieden allemaal een abstractie over een blok geheugen dat een matrix met vergelijkbare elementen opslaat. Het verschil is dat Span<T> en ReadOnlySpan<T> zijn ref struct typen terwijl Memory<T> en ReadOnlyMemory<T> zijn struct typen. Span-elementen bevatten een ref field. Daarom kunnen exemplaren van een span de veilige context niet verlaten. De veilige context van een ref struct is de ref veilige context van zijn ref field. De implementatie van Memory<T> en ReadOnlyMemory<T> verwijder deze beperking. U gebruikt deze typen om rechtstreeks toegang te krijgen tot geheugenbuffers.
Prestaties verbeteren met refveiligheid
Als u deze functies gebruikt om de prestaties te verbeteren, worden de volgende taken uitgevoerd:
-
Vermijd toewijzingen: wanneer u een type wijzigt van een
classin eenstruct, wijzigt u de manier waarop het wordt opgeslagen. Lokale variabelen worden opgeslagen op de stack. Leden worden inline opgeslagen wanneer het containerobject wordt toegewezen. Deze wijziging betekent minder toewijzingen en dat vermindert het werk dat de garbagecollector doet. Het kan ook de geheugendruk verminderen, zodat de vuilnisopruimer minder vaak hoeft te draaien. -
Behoud de verwijzingsemantiek: als u een type wijzigt van een
classin eenstructvariabele, wijzigt u de semantiek van het doorgeven van een variabele aan een methode. Code die de status van de parameters heeft gewijzigd, moet worden gewijzigd. Nu de parameter eenstructis, wijzigt de methode een kopie van het oorspronkelijke object. U kunt de oorspronkelijke semantiek herstellen door die parameter door te geven als parameterref. Na deze wijziging wordt de oorspronkelijkestructmethode opnieuw gewijzigd. -
Vermijd het kopiëren van gegevens: het kopiëren van grotere
structtypen kan van invloed zijn op de prestaties in sommige codepaden. U kunt ook derefmodifier toevoegen om grotere gegevensstructuren door referentie aan methoden door te geven in plaats van op waarde. -
Wijzigingen beperken: wanneer een
structtype wordt doorgegeven door verwijzing, kan de aangeroepen methode de status van de struct wijzigen. U kunt derefwijzigingsfunctie vervangen door deref readonlyofinmodifiers om aan te geven dat het argument niet kan worden gewijzigd. Geef de voorkeur aanref readonlywanneer de methode de parameter vastlegt of deze retourneert als een 'readonly' referentie. U kunt ookreadonly structtypen ofstructtypen maken metreadonlyleden om meer controle te bieden over welke leden van eenstructkunnen worden gewijzigd. -
Geheugen rechtstreeks bewerken: sommige algoritmen zijn het efficiëntst bij het behandelen van gegevensstructuren als een blok geheugen dat een reeks elementen bevat. De
SpantypenMemorybieden veilige toegang tot blokken geheugen.
Voor geen van deze technieken is code vereist unsafe . U kunt op verstandige wijze prestatiekenmerken verkrijgen van veilige code die voorheen alleen mogelijk was door onveilige technieken te gebruiken. U kunt de technieken zelf proberen in de zelfstudie over het verminderen van geheugentoewijzingen.