Optimalizace výkonu: Chování objektů
Pochopení vnitřního chování objektů WPF vám pomůže zajistit správné kompromisy mezi funkcemi a výkonem.
Neodstranění obslužných rutin událostí u objektů může udržovat objekty naživu
Delegát, který objekt předává do své události, je efektivně odkazem na tento objekt. Obslužné rutiny událostí proto mohou udržovat objekty naživu déle, než se čekalo. Při provádění úklidu objektu, který je zaregistrovaný pro naslouchání událostem objektu, je nezbytné odebrat tohoto delegáta před uvolněním onoho objektu. Udržování nepotřebných objektů naživu zvyšuje využití paměti aplikace. To platí zejména v případě, že objekt je kořenem logického stromu nebo vizuálního stromu.
WPF zavádí vzor slabého posluchače událostí pro události, které mohou být užitečné v situacích, kdy je těžké sledovat vztahy životnosti objektů mezi zdrojem a posluchačem. Tento vzor používají některé existující události WPF. Pokud implementujete objekty s vlastními událostmi, může být tento vzor použit pro vás. Podrobnosti najdete v vzorech slabých událostí.
Existuje několik nástrojů, jako je profiler CLR a prohlížeč pracovních skupin, které mohou obsahovat informace o využití paměti zadaného procesu. Profiler CLR obsahuje řadu velmi užitečných zobrazení profilu přidělení, včetně histogramu přidělených typů, grafů přidělení a volání, časového řádku zobrazující uvolňování paměti různých generací a výsledný stav spravované haldy za těmito kolekcemi a strom volání zobrazující přidělení jednotlivých metod a načtení sestavení. Další informace naleznete v tématu Výkon.
Vlastnosti a objekty závislostí
Obecně platí, že přístup k vlastnosti závislosti DependencyObject není pomalejší než přístup k vlastnosti CLR. I když je pro nastavení hodnoty vlastnosti menší režie výkonu, získání hodnoty je stejně rychlé jako získání hodnoty z vlastnosti CLR. Vyvážení malé výkonové režie je skutečnost, že vlastnosti závislostí podporují robustní funkce, jako jsou datové vazby, animace, dědičnost a stylování. Další informace najdete v tématu Přehled vlastností závislosti.
Optimalizace DependencyProperty
Vlastnosti závislostí byste ve své aplikaci měli definovat velmi pečlivě. Pokud vaše DependencyProperty ovlivňuje možnosti metadat typu vykreslení místo jiných možností metadat, jako je AffectsMeasure, měli byste to označit jako takové přepsáním jeho metadat. Další informace o přepsání nebo získávání metadat vlastností naleznete v tématu Metadata vlastností závislostí.
Může být efektivnější, aby obslužná rutina změn vlastností ručně invalidovala procesy měření, uspořádávání a vykreslování, pokud ne všechny změny vlastností skutečně tyto procesy ovlivňují. Můžete se například rozhodnout znovu vykreslit pozadí jenom v případě, že je hodnota větší než nastavený limit. V tomto případě by obslužná rutina změny vlastnosti zneplatnila vykreslení pouze v případě, že hodnota překročí nastavený limit.
Vytvoření zděděné závislosti není zadarmo
Ve výchozím nastavení jsou registrované vlastnosti závislostí neděditelné. Můžete však explicitně vytvořit libovolnou zděděnou vlastnost. I když je to užitečná funkce, převod vlastnosti, která má být zděděná, má vliv na výkon zvýšením doby pro zneplatnění vlastnosti.
Při používání funkce RegisterClassHandler buďte opatrní.
Voláním RegisterClassHandler je možné uložit stav instance, je však důležité vědět, že zpracování probíhá u každé instance, což může mít negativní dopad na výkon. Použijte RegisterClassHandler jenom v případě, že vaše aplikace vyžaduje uložení stavu instance.
Nastavení výchozí hodnoty pro DependencyProperty během registrace
Při vytváření DependencyProperty, která vyžaduje výchozí hodnotu, nastavte hodnotu pomocí výchozích metadat předaných jako parametr do Register metody DependencyProperty. Tuto techniku použijte místo nastavení hodnoty vlastnosti v konstruktoru nebo u každé instance prvku.
Nastavení hodnoty PropertyMetadata pomocí registru
Při vytváření DependencyPropertymáte možnost nastavit PropertyMetadata pomocí metod Register nebo OverrideMetadata. I když objekt může mít statický konstruktor pro volání OverrideMetadata, nejedná se o optimální řešení a bude mít vliv na výkon. Nejlepšího výkonu dosáhnete nastavením PropertyMetadata během volání na Register.
Ukotvené objekty
Freezable je speciální typ objektu se dvěma stavy: rozmrazený a zmrazený. Zmrazení objektů, kdykoli je to možné, zlepší výkon aplikace a sníží jeho pracovní sadu. Další informace naleznete v tématu Přehled zamrznutelných objektů .
Každý Freezable má událost Changed, která se vyvolá, kdykoli se změní. Oznámení o změnách jsou ale nákladná z hlediska výkonu aplikace.
Podívejte se na následující příklad, ve kterém každý Rectangle používá stejný objekt Brush:
rectangle_1.Fill = myBrush;
rectangle_2.Fill = myBrush;
rectangle_3.Fill = myBrush;
// ...
rectangle_10.Fill = myBrush;
rectangle_1.Fill = myBrush
rectangle_2.Fill = myBrush
rectangle_3.Fill = myBrush
' ...
rectangle_10.Fill = myBrush
WPF ve výchozím nastavení poskytuje obslužnou rutinu pro událost Changed u objektu SolidColorBrush pro zneplatnění vlastnosti Fill objektu Rectangle. V takovém případě je pokaždé, když SolidColorBrush aktivovat svou Changed událost, nutné vyvolat funkci zpětného volání pro každou Rectangle—nahromadění těchto volání představuje významnou ztrátu výkonu. Kromě toho je velmi náročné na výkon přidávat a odebírat obslužné rutiny v tomto okamžiku, protože aplikace by musela procházet celý seznam. Pokud váš scénář aplikace nikdy nezmění SolidColorBrush, budete zbytečně platit náklady na údržbu Changed obslužných rutin událostí.
Zmrazení Freezable může zlepšit jeho výkon, protože už nemusí vynakládat prostředky na údržbu oznámení o změnách. Následující tabulka ukazuje velikost jednoduchého SolidColorBrush, pokud je jeho vlastnost IsFrozen nastavena na true
, ve srovnání s tím, kdy není. To předpokládá použití jednoho nástroje na vlastnost Fill u deseti objektů Rectangle.
stavu | velikost |
---|---|
Zmrazené SolidColorBrush | 212 bajtů |
Nezamrzlé SolidColorBrush | 972 Bajty |
Následující ukázka kódu ukazuje tento koncept:
Brush frozenBrush = new SolidColorBrush(Colors.Blue);
frozenBrush.Freeze();
Brush nonFrozenBrush = new SolidColorBrush(Colors.Blue);
for (int i = 0; i < 10; i++)
{
// Create a Rectangle using a non-frozed Brush.
Rectangle rectangleNonFrozen = new Rectangle();
rectangleNonFrozen.Fill = nonFrozenBrush;
// Create a Rectangle using a frozed Brush.
Rectangle rectangleFrozen = new Rectangle();
rectangleFrozen.Fill = frozenBrush;
}
Dim frozenBrush As Brush = New SolidColorBrush(Colors.Blue)
frozenBrush.Freeze()
Dim nonFrozenBrush As Brush = New SolidColorBrush(Colors.Blue)
For i As Integer = 0 To 9
' Create a Rectangle using a non-frozed Brush.
Dim rectangleNonFrozen As New Rectangle()
rectangleNonFrozen.Fill = nonFrozenBrush
' Create a Rectangle using a frozed Brush.
Dim rectangleFrozen As New Rectangle()
rectangleFrozen.Fill = frozenBrush
Next i
Změněné obslužné rutiny u neuzamrzlých objektů, které lze zmrazit, mohou udržovat objekty naživu.
Delegát, který objekt předá Freezable události Changed objektu, je efektivně odkazem na tento objekt. Proto Changed obslužné rutiny událostí mohou udržovat objekty naživu déle, než se čekalo. Při čištění objektu, který je zaregistrovaný k naslouchání Changed události Freezable objektu, je důležité odebrat tento delegát před uvolněním objektu.
WPF také interně zachytává události Changed. Například všechny vlastnosti závislostí, které mají Freezable jako hodnotu, budou automaticky naslouchat událostem Changed. Vlastnost Fill, která přebírá Brush, ilustruje tento koncept.
Brush myBrush = new SolidColorBrush(Colors.Red);
Rectangle myRectangle = new Rectangle();
myRectangle.Fill = myBrush;
Dim myBrush As Brush = New SolidColorBrush(Colors.Red)
Dim myRectangle As New Rectangle()
myRectangle.Fill = myBrush
Při přiřazení myBrush
do myRectangle.Fill
se delegát, který odkazuje zpět na objekt Rectangle, přidá do události Changed objektu SolidColorBrush. To znamená, že následující kód ve skutečnosti nečiní myRect
způsobilým k uvolňování paměti.
myRectangle = null;
myRectangle = Nothing
V tomto případě myBrush
stále udržuje myRectangle
naživu a zavolá k němu zpět, když aktivuje událost Changed. Všimněte si, že přiřazení myBrush
k vlastnosti Fill nového Rectangle jednoduše přidá další obslužnou rutinu události do myBrush
.
Doporučeným způsobem čištění těchto typů objektů je odebrání Brush z vlastnosti Fill, která pak odebere obslužnou rutinu události Changed.
myRectangle.Fill = null;
myRectangle = null;
myRectangle.Fill = Nothing
myRectangle = Nothing
Virtualizace uživatelského rozhraní
WPF také nabízí variantu elementu StackPanel, která automaticky "virtualizuje" obsah vázaný na data. V tomto kontextu slovo virtualizuje techniku, pomocí které se podmnožina objektů generuje z většího počtu datových položek na základě toho, které položky jsou viditelné na obrazovce. Je náročné, jak z hlediska paměti, tak procesoru, vygenerovat velký počet prvků uživatelského rozhraní, když v daném okamžiku může být na obrazovce jen několik. VirtualizingStackPanel (prostřednictvím funkcí poskytovaných VirtualizingPanel) vypočítá viditelné položky a pracuje s ItemContainerGenerator z ItemsControl (například ListBox nebo ListView) a vytváří prvky jenom pro viditelné položky.
Při optimalizaci výkonu se vizuální objekty pro tyto položky generují nebo udržují aktivní pouze v případě, že jsou viditelné na obrazovce. Pokud už nejsou v zobrazitelné oblasti ovládacího prvku, mohou být objekty vizuálu odebrány. To není zaměňováno s virtualizací dat, kdy datové objekty nejsou všechny v místní kolekci, spíše streamovány podle potřeby.
Následující tabulka ukazuje uplynulý čas přidání a vykreslení 5000 prvků TextBlock do StackPanel a VirtualizingStackPanel. V tomto scénáři měření představují čas mezi připojením textového řetězce k vlastnosti ItemsSource objektu ItemsControl k času, kdy prvky panelu zobrazí textový řetězec.
panelu hostitelů |
doba vykreslování (ms) |
---|---|
StackPanel | 3210 |
VirtualizingStackPanel | 46 |
Viz také
- optimalizace výkonu aplikací WPF
- Plánování výkonu aplikací
- Využití možností hardwaru
- rozložení a návrhové
-
2D grafika a zobrazení - prostředky aplikace
- Text
- Datové vazby
- dalších doporučení k výkonu
.NET Desktop feedback