Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Fontos
Az ebben a szakaszban ismertetett technikák javítják a teljesítményt a kód gyakori elérési útjaira alkalmazva. A gyakori elérési utak a kódbázis azon szakaszai, amelyeket a normál műveletek során gyakran és ismétlődően hajtanak végre. Ezeknek a technikáknak a gyakran nem végrehajtott kódokra való alkalmazása minimális hatással lesz. Mielőtt bármilyen módosítást végeznénk a teljesítmény javítása érdekében, kritikus fontosságú az alapkonfiguráció mérése. Ezután elemezze az alapállapotot annak meghatározásához, hogy hol fordulnak elő memória szűk keresztmetszetek. Számos platformfüggetlen eszközzel mérheti az alkalmazás teljesítményét a Diagnosztika és a rendszerállapot című szakaszban. A Visual Studio dokumentációjában a memóriahasználat mérésére vonatkozó oktatóanyagban gyakorolhat profilkészítési munkamenetet.
Miután felmérte a memóriahasználatot, és megállapította, hogy csökkentheti a foglalásokat, az ebben a szakaszban ismertetett technikákkal csökkentheti a foglalásokat. Minden egymást követő módosítás után ismét mérje meg a memóriahasználatot. Győződjön meg arról, hogy minden módosítás pozitív hatással van az alkalmazás memóriahasználatára.
A .NET teljesítménybeli működése gyakran azt jelenti, hogy eltávolítja a foglalásokat a kódból. Végül minden lefoglalt memóriablokkot felszabadítani kell. Kevesebb foglalás csökkenti a szemétgyűjtésben töltött időt. Kiszámíthatóbb végrehajtási időt tesz lehetővé azáltal, hogy eltávolítja a szemétgyűjtéseket bizonyos kódelérési utakról.
A foglalások csökkentésének gyakori taktikája a kritikus adatstruktúrák class típusúakról struct típusúakra való átalakítása. Ez a változás hatással van az ilyen típusú használat szemantikára. A paramétereket és a visszatérési értékeket mostantól érték szerint adjuk át, nem pedig hivatkozással. Az érték másolásának költsége elhanyagolható, ha a típusok kicsik, három szó vagy kevesebb (figyelembe véve, hogy egy szó természetes méretű egy egész szám). Mérhető, és a nagyobb típusok teljesítményére is hatással lehet. A másolás hatásának leküzdése érdekében a fejlesztők át tudják adni ezeket a típusokat ref a tervezett szemantikák visszaállításához.
A C# ref -funkciók lehetővé teszik a típusok kívánt szemantikájának struct kifejezését anélkül, hogy az negatív hatással lenne az általános használhatóságukra. A fejlesztések előtt a fejlesztőknek mutatókkal és nyers memóriával rendelkező szerkezeteket kellett alkalmazniuk unsafe , hogy ugyanazt a teljesítményhatást érjék el. A fordító ellenőrizhetően biztonságos kódot hoz létre az új ref kapcsolódó funkciókhoz.
A ellenőrizhetően biztonságos kód azt jelenti, hogy a fordító észleli a lehetséges puffertúlcsordulásokat, illetve a nem foglalt vagy szabad memória elérését. A fordító észleli és megakadályozza a hibákat.
Átadás és visszaadás referenciaként
A C# nyelvben a változók értékeket tárolnak. A struct típusok esetén az érték a típus egy példányának tartalma. Típusok esetén class az érték egy memóriablokkra mutató hivatkozás, amely a típus egy példányát tárolja. A ref módosító hozzáadása azt jelenti, hogy a változó tárolja az értékre mutató hivatkozást . Az struct típusoknál a hivatkozás az értéket tartalmazó tárolóra mutat. A class típusok esetén a referencia a tárolóra mutat, amely tartalmazza a memóriablokkra mutató hivatkozást.
A C#-ban a metódusok paramétereit érték szerint adja át a rendszer, a visszaadott értékeket pedig érték szerint adja vissza. Az argumentum értéke a metódusnak lesz átadva. A visszatérési argumentum értéke a visszatérési érték.
A ref, in, ref readonlyvagy out módosító azt jelzi, hogy az argumentumot hivatkozással adja át. A metódus a tárolási helyre mutató hivatkozást ad át. Ha a metódus szignatúrájához hozzáadja a ref, ez azt jelenti, hogy a visszaadott érték hivatkozásként tér vissza. A tárhelyre mutató hivatkozás a visszatérési érték.
A ref-hozzárendeléssel azt is megteheti, hogy egy változó egy másik változóra hivatkozik. Egy tipikus hozzárendelés a jobb oldali értékeket a hozzárendelés bal oldalán lévő változóba másolja. A ref-hozzárendelés a változó memóriahelyét a jobb oldalon a bal oldalon lévő változóra másolja. A ref most az eredeti változóra hivatkozik:
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
Amikor hozzárendel egy változót, megváltoztatja annak értékét. Amikor újra hozzárendel egy változót, megváltoztatja, amire hivatkozik.
A ref változókkal közvetlenül is dolgozhat az értékek tárolásával, hivatkozás általi továbbítással és ref-hozzárendeléssel. A fordító által érvényesített hatókörszabályok biztosítják a biztonságot tárolókezelés során.
A ref readonly és in módosítók egyaránt jelzik, hogy az argumentumot hivatkozásként kell átadni, és nem lehet újra hozzárendelni a metódusban. A különbség az, hogy azt jelzi, ref readonly hogy a metódus a paramétert változóként használja. A metódus rögzítheti a paramétert, vagy könnyen hivatkozva visszaadhatja a paramétert. Ezekben az esetekben a ref readonly módosító használata ajánlott. Ellenkező esetben a in módosító nagyobb rugalmasságot biztosít. Nem kell hozzáadnia a in módosítót egy in paraméter argumentumához, így a módosító használatával biztonságosan frissítheti a in meglévő API-aláírásokat. A fordító figyelmeztetést ad ki, ha nem adja hozzá az argumentumhoz a ref vagy in módosítót egy ref readonly paraméter esetén.
Biztonságos környezet kontextusa
A C# a kifejezésekre vonatkozó ref szabályokat tartalmaz, amelyek biztosítják, hogy egy ref kifejezés ne legyen elérhető ott, ahol a hivatkozott tároló már nem érvényes. Vegye figyelembe a következő példát:
public ref int CantEscape()
{
int index = 42;
return ref index; // Error: index's ref safe context is the body of CantEscape
}
A fordító hibát jelez, mert nem tud helyi változóra mutató hivatkozást visszaadni egy metódusból. A hívó nem tudja elérni a hivatkozott tárolót. A ref safe környezet határozza meg azt a hatókört, amelyben egy ref kifejezés biztonságosan elérhető vagy módosítható. Az alábbi táblázat a változótípusok biztonságos ref-környezeteit sorolja fel.
ref mezők nem deklarálhatók class vagy nemReferencia struct-ben, ezért ezek a sorok nem találhatók a táblában.
| Nyilatkozat | ref biztonságos környezet |
|---|---|
| nem referencia helyi | az a blokk, ahol a lokális változó deklarálva van |
| nem referencia paraméter | aktuális metódus |
ref, ref readonly, in paraméter |
hívási módszer |
out paraméter |
aktuális metódus |
class mező |
hívási módszer |
nem referencia struct mező |
aktuális metódus |
ref mezője ref struct |
hívási módszer |
Egy változó akkor adható ref vissza, ha a ref biztonságos környezete a hívási módszer. Ha a ref biztonságos környezete az aktuális metódus vagy blokk, nem engedélyezett a ref visszatérés. Az alábbi kódrészlet két példát mutat be. A tagmezők a metódust hívó hatókörből érhetők el, így az osztály- vagy struktúramező biztonságos környezete a hívási módszer. A , vagy ref módosítókkal rendelkező paraméterek in az egész módszer. Mindkettő visszaadható ref tagmetódusból:
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;
}
Megjegyzés:
Amikor a ref readonly vagy in módosítót alkalmazzák egy paraméterre, az a paraméter ref readonly által adható vissza, és nem ref által.
A fordító biztosítja, hogy egy hivatkozás ne meneküljön el a ref biztonságos környezetéből. Biztonságosan használhatja a ref paramétereket, a ref return, és a ref helyi változókat, mert a fordító automatikusan észleli, ha véletlenül olyan ref kódot ír, amely akkor lenne hozzáférhető, amikor a tárhely érvénytelen.
Biztonságos környezet és referenciastruktúrák
ref struct a típusok több szabályt igényelnek a biztonságos használatuk érdekében. Egy ref struct típus tartalmazhat ref mezőket. Ehhez szükség van egy biztonságos környezet bevezetésére. A legtöbb típus esetében a biztonságos környezet a hívási módszer. Más szóval egy nem egy ref struct érték mindig visszaadható egy metódusból.
Informálisan a biztonságos környezet a ref struct esetében az a hatókör, ahol az összes ref mező elérhető. Más szóval, ez az összes mezőnek a ref biztonságos környezete metszetével azonos. A következő függvény visszatér egy ReadOnlySpan<char> tagmezőre, tehát a biztonságos környezet maga a függvény.
private string longMessage = "This is a long message";
public ReadOnlySpan<char> Safe()
{
var span = longMessage.AsSpan();
return span;
}
Ezzel szemben a következő kód hibát ad ki, mert a ref field a Span<int> tag az egész számokat tartalmazó verembe foglalt tömbre hivatkozik. Nem tud kikerülni a metódusból:
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.
}
Memóriatípusok egyesítése
Az System.Span<T> és System.Memory<T> bevezetése egy egységes modellt kínál a memória kezeléséhez.
System.ReadOnlySpan<T> és System.ReadOnlyMemory<T> biztosítson olvasható verziókat a memória eléréséhez. Ezek mind absztrakciót biztosítanak egy hasonló elemeket tartalmazó memóriablokk felett. A különbség az, hogy Span<T> és ReadOnlySpan<T>ref struct típusok, míg Memory<T> és ReadOnlyMemory<T>struct típusok. A spanok tartalmaznak egy ref field. Ezért a span példányai nem hagyhatják el a biztonságos környezetet. A biztonságos környezet a ref structref biztonságos környezete.ref field A Memory<T> és ReadOnlyMemory<T> megvalósítása megszünteti ezt a korlátozást. Ezekkel a típusokkal közvetlenül érheti el a memóriapuffereket.
Teljesítmény javítása a ref biztonságával
Az alábbi funkciók a teljesítmény javítása érdekében az alábbi feladatokat foglalják magukban:
-
Kerülje a foglalásokat: Ha egy típust
class-rólstruct-ra módosít, megváltozik annak tárolási módja. A helyi változók a veremen vannak tárolva. A tagok inline módon vannak tárolva, amikor a tároló objektum lefoglalásra kerül. Ez a változás kevesebb foglalást jelent, és csökkenti a szemétgyűjtő által végzett munkát. Csökkentheti a memóriaterhelést is, így a szemétgyűjtő ritkábban fut. -
A referencia szemantikájának megőrzése: Egy típus módosítása egy
classstructváltozó metódusnak való átadásának szemantikáját módosítja. Módosítani kell a paraméterek állapotát módosító kódot. Most, hogy a paraméter egystruct, a metódus módosítja az eredeti objektum másolatát. Az eredeti szemantikát visszaállíthatja úgy, hogy paraméterként adja át a paramétertref. A módosítás után a metódus újra módosítja az eredetitstruct. -
Kerülje az adatok másolását: A nagyobb
structtípusok másolása hatással lehet bizonyos kódútvonalak teljesítményére. Azt is hozzáadhatja arefmódosítóhoz, hogy nagyobb adatstruktúrát adjon át a metódusokhoz hivatkozással, nem pedig érték alapján. -
Módosítások korlátozása: Ha egy
structtípust hivatkozással ad át, a hívott metódus módosíthatja a szerkezet állapotát. Lecserélheti arefmódosítót aref readonlyvagyinmódosítókra, hogy jelezze, az argumentum nem módosítható. Előnyben részesítseref readonly, ha a metódus rögzíti a paramétert, vagy readonly hivatkozással adja vissza. Azreadonly structtípusokat vagystructtípusokat létrehozhat, amelyekreadonlytagokkal rendelkeznek, hogy jobban szabályozhassa, mely tagjai módosíthatók egystruct-nak. -
A memória közvetlen kezelése: Egyes algoritmusok akkor a leghatékonyabbak, ha az adatstruktúrákat elemek sorozatát tartalmazó memóriablokkként kezelik. A
SpanésMemorytípusok biztonságosan biztosítanak hozzáférést a memóriablokkokhoz.
Ezen technikák egyike sem igényel unsafe kódot. Okosan használva olyan biztonságos kódból kaphat teljesítményjellemzőket, amelyek korábban csak nem biztonságos technikákkal lehetségesek. A memóriafoglalások csökkentéséről szóló oktatóanyagban saját maga is kipróbálhatja a technikákat.