Poznámka
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Důležité
Techniky popsané v této části zlepšují výkon při použití na kritické úseky v kódu. Horké části jsou úseky kódové základny, které se běžně a opakovaně spouští během běžných operací. Použití těchto technik na kód, který se často nespustí, bude mít minimální dopad. Před provedením jakýchkoli změn ke zlepšení výkonu je důležité měřit základní úroveň. Pak analyzujte tuto základní úroveň a zjistěte, kde dochází k úzkým místům paměti. O mnoha nástrojích pro různé platformy, které měří výkon vaší aplikace, najdete v části Diagnostika a instrumentace. V průvodci si můžete procvičit profilovací relaci pro měření využití paměti v dokumentaci Visual Studio.
Jakmile změříte využití paměti a zjistíte, že můžete snížit přidělení, snižte přidělení pomocí technik v této části. Po každé následné změně změřte využití paměti znovu. Ujistěte se, že každá změna má pozitivní vliv na využití paměti ve vaší aplikaci.
Optimalizace výkonu v .NET často znamená odebrání alokací z vašeho kódu. Každý blok paměti, který přidělíte, musí být nakonec uvolněn. Méně alokací zkracuje čas na sběr odpadu. Umožňuje předvídatelnější dobu provádění odstraněním procesů uvolňování paměti z konkrétních částí kódu.
Běžnou taktikou redukce přidělení je změna důležitých datových struktur z class
typů na struct
typy. Tato změna má vliv na sémantiku použití těchto typů. Parametry a návratové hodnoty se teď předávají hodnotou místo odkazu. Náklady na kopírování hodnoty jsou zanedbatelné, pokud jsou typy malé, tři nebo méně slov (vzhledem k tomu, že jedno slovo je přirozené velikosti jednoho celého čísla). Je měřitelný a může mít skutečný dopad na výkon u větších typů. Aby vývojáři mohli bojovat proti účinku kopírování, mohou tyto typy ref
předat, aby získali zpět zamýšlenou sémantiku.
Funkce jazyka C# ref
umožňují vyjádřit požadovanou sémantiku pro struct
typy bez negativního dopadu na jejich celkovou použitelnost. Před těmito vylepšeními se vývojáři museli uchylovat k unsafe
konstruktorům s ukazateli a nezpracovanou pamětí, aby dosáhli stejného dopadu na výkon. Kompilátor generuje ověřitelně bezpečný kód pro nové ref
související funkce.
Ověřitelně bezpečný kód znamená, že kompilátor detekuje možné přetečení vyrovnávací paměti nebo přístup k nepřidělené nebo uvolněné paměti. Kompilátor zjistí a zabraňuje některým chybám.
Předání a vrácení odkazem
Proměnné v jazyce C# uchovávají hodnoty. V struct
typech je hodnota obsahem instance typu. V class
typech je hodnota odkazem na blok paměti, který ukládá instanci typu. Přidání modifikátoru ref
znamená, že proměnná ukládá odkaz na hodnotu. Ve struct
typech odkazuje referenční bod na úložiště obsahující hodnotu. V typech class
odkaz směřuje k úložišti obsahujícímu odkaz na blok paměti.
V jazyce C# jsou parametry metod předány podle hodnoty a návratové hodnoty jsou vráceny hodnotou. Hodnota argumentu je předána metodě. Hodnota návratového argumentu je návratová hodnota.
Modifikátor ref
, in
, ref readonly
nebo out
označuje, že argument je předán odkazem. Do metody se předá odkaz na umístění úložiště. Přidání ref
do podpisu metody znamená, že návratová hodnota je vrácena odkazem.
Odkaz na umístění úložiště je návratová hodnota.
Přiřazení ref můžete použít také k tomu, aby proměnná odkazovala na jinou proměnnou. Typické přiřazení zkopíruje hodnotu z pravé strany do proměnné na levé straně přiřazení.
Přiřazení odkazu zkopíruje paměťovou adresu proměnné na pravé straně na proměnnou na levé straně. Nyní ref
odkazuje na původní proměnnou:
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
Když přiřadíte proměnnou, změníte její hodnotu. Když přiřadíte odkazem proměnnou, změníte, na co odkazuje.
Můžete pracovat přímo s úložištěm pro hodnoty pomocí ref
proměnných, předávání podle odkazu a přiřazení pomocí odkazu. Pravidla oboru vynucovaná kompilátorem zajišťují bezpečnost při práci přímo s úložištěm.
ref readonly
a in
oba modifikátory naznačují, že argument by měl být předán odkazem a nelze jej znovu přiřadit v metodě. Rozdíl je, že ref readonly
metoda používá parametr jako proměnnou. Metoda může zachytit parametr, nebo může vrátit parametr jako referenci, pouze pro čtení. V takových případech byste měli použít ref readonly
modifikátor.
in
V opačném případě modifikátor nabízí větší flexibilitu. Modifikátor in
není potřeba přidávat k argumentu pro parametr in
, takže stávající podpisy rozhraní API lze bezpečně aktualizovat pomocí modifikátoru in
. Kompilátor vydá upozornění, pokud do argumentu ref
parametru nepřidáte in
ani ref readonly
modifikátor.
Referenční bezpečný kontext
Jazyk C# obsahuje pravidla pro výrazy, ref
aby se zajistilo, že výraz nebude přístupný tam, ref
kde úložiště, na které odkazuje, už není platné. Podívejte se na následující příklad:
public ref int CantEscape()
{
int index = 42;
return ref index; // Error: index's ref safe context is the body of CantEscape
}
Kompilátor hlásí chybu, protože z metody nelze vrátit odkaz na místní proměnnou. Volající nemá přístup k úložišti, na které se odkazuje. Kontext ref safe definuje obor, ve kterém je ref
výraz bezpečný pro přístup nebo úpravu. Následující tabulka uvádí referenční bezpečné kontexty pro typy proměnných .
ref
pole se nedají deklarovat v class
ani v ne-referenčním struct
, takže tyto řádky nejsou v tabulce:
Prohlášení | Referenční bezpečný kontext |
---|---|
místní bez reference | blok, kde je lokální deklarován |
parametr nenázvový | aktuální metoda |
ref , ref readonly , in parametr |
metoda volání |
out parametr |
aktuální metoda |
class pole |
metoda volání |
pole bez odkazu struct |
aktuální metoda |
ref pole ref struct |
metoda volání |
Proměnnou lze ref
vrátit, pokud je jejím referenčním bezpečným kontextem volání metoda. Pokud je jeho referenční bezpečný kontext aktuální metodou nebo blokem, ref
vrácení je zakázáno. Následující fragment kódu ukazuje dva příklady. K poli člena lze přistupovat z oboru volajícího metody, takže bezpečný referenční kontext pole třídy nebo struktury je volající metoda. Referenční bezpečný kontext pro parametr s modifikátory ref
nebo in
je celá metoda. Obě je možné ref
vrátit z metody člena:
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;
}
Poznámka:
Když je modifikátor ref readonly
nebo in
použit na parametr, tento parametr může být vrácen pomocí ref readonly
, nikoli ref
.
Kompilátor zajišťuje, že odkaz nemůže opustit svůj bezpečný kontext pro odkazy. Parametry ref
a místní proměnné ref return
a ref
můžete bezpečně používat, protože kompilátor zjistí, jestli jste náhodou napsali kód, ve kterém by se výraz ref
mohl použít, když jeho úložiště není platné.
Bezpečný kontext a referenční struktury
ref struct
typy vyžadují více pravidel, aby se zajistilo jejich bezpečné použití. Typ ref struct
může obsahovat ref
pole. To vyžaduje zavedení bezpečného kontextu. U většiny typů je bezpečný kontext volající metodou. Jinými slovy, hodnota, která není ref struct
, může být vždy vrácena z metody.
Neformálně platí, že bezpečný kontext pro ref struct
je rozsah, ve kterém jsou dostupná všechna jeho ref
pole. Jinými slovy, jedná se o průsečík bezpečného kontextu odkazu všech jeho ref
polí. Následující metoda vrátí pole člena ReadOnlySpan<char>
, takže jeho bezpečný kontext je metoda:
private string longMessage = "This is a long message";
public ReadOnlySpan<char> Safe()
{
var span = longMessage.AsSpan();
return span;
}
Naproti tomu následující kód vygeneruje chybu, protože ref field
člen Span<int>
odkazuje na pole přidělené zásobníku celých čísel. Nelze se vyhnout metodě:
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.
}
Sjednocení typů paměti
Zavedení System.Span<T> a System.Memory<T> poskytují jednotný model pro práci s pamětí.
System.ReadOnlySpan<T> a System.ReadOnlyMemory<T> poskytují verze pouze pro čtení pro přístup k paměti. Všechny poskytují abstrakci nad blokem paměti, který ukládá pole podobných prvků. Rozdíl je v tom, že Span<T>
a ReadOnlySpan<T>
jsou ref struct
typy, zatímco Memory<T>
a ReadOnlyMemory<T>
jsou struct
typy. Rozpětí obsahují ref field
. Instance úseku proto nemohou opustit svůj bezpečný kontext.
Bezpečným kontextemref struct
je ref bezpečný kontext jeho ref field
. Implementace Memory<T>
a ReadOnlyMemory<T>
odstraňují toto omezení. Tyto typy slouží k přímému přístupu k paměťovým bufferům.
Zvýšení výkonu s využitím bezpečnosti ref
Použití těchto funkcí ke zlepšení výkonu zahrnuje tyto úlohy:
-
Vyhněte se alokací: Když změníte typ z
class
nastruct
, změníte způsob jeho uložení. Místní proměnné jsou uloženy v zásobníku. Členové se ukládají v textu při přidělení objektu kontejneru. Tato změna znamená méně alokací, což sníží množství práce, kterou systém uvolňování paměti vykoná. Může také snížit zatížení paměti, aby garbage collector běžel méně často. -
Zachování sémantiky odkazu: Změna typu z
class
nastruct
může změnit sémantiku předání proměnné metodě. Kód, který změnil stav parametrů, potřebuje upravit. Nyní, když je parametrstruct
, metoda upravuje kopii původního objektu. Původní sémantiku můžete obnovit předáním parametru jako parametruref
. Po této změně metoda znovu upraví původnístruct
. -
Vyhněte se kopírování dat: Kopírování větších
struct
typů může mít vliv na výkon v některých cestách kódu. Můžete také přidat modifikátorref
pro předání větších datových struktur metodám odkazem místo podle hodnoty. -
Omezit úpravy: Pokud je typ
struct
předán odkazem, volaná metoda může změnit stav struktury. Modifikátorref
můžete nahraditref readonly
modifikátory neboin
modifikátory, které indikují, že argument nelze upravit. Preferujteref readonly
, když metoda zachytí parametr nebo ho vrátí prostřednictvím referencí jen pro čtení. Můžete také vytvářetreadonly struct
typy nebostruct
typy sereadonly
členy, abyste měli větší kontrolu nad tím, jaké členystruct
lze upravovat. -
Přímá manipulace s pamětí: Některé algoritmy jsou nejúčinnější při zpracování datových struktur jako bloku paměti obsahující posloupnost prvků. Typy
Span
aMemory
poskytují bezpečný přístup k blokům paměti.
Žádná z těchto technik nevyžaduje unsafe
kód. Používá se moudře, můžete získat charakteristiky výkonu z bezpečného kódu, který byl dříve možný pouze pomocí nebezpečných technik. Techniky můžete vyzkoušet sami v tomto kurzu o snížení přidělení paměti.