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 readonly in |
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
class
in 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
class
in eenstruct
variabele, 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 eenstruct
is, 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 oorspronkelijkestruct
methode opnieuw gewijzigd. -
Vermijd het kopiëren van gegevens: het kopiëren van grotere
struct
typen kan van invloed zijn op de prestaties in sommige codepaden. U kunt ook deref
modifier toevoegen om grotere gegevensstructuren door referentie aan methoden door te geven in plaats van op waarde. -
Wijzigingen beperken: wanneer een
struct
type wordt doorgegeven door verwijzing, kan de aangeroepen methode de status van de struct wijzigen. U kunt deref
wijzigingsfunctie vervangen door deref readonly
ofin
modifiers om aan te geven dat het argument niet kan worden gewijzigd. Geef de voorkeur aanref readonly
wanneer de methode de parameter vastlegt of deze retourneert als een 'readonly' referentie. U kunt ookreadonly struct
typen ofstruct
typen maken metreadonly
leden om meer controle te bieden over welke leden van eenstruct
kunnen 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
Span
typenMemory
bieden 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.