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.
Ha Win2D-vezérlőket használ felügyelt XAML-alkalmazásokban, ügyelni kell arra, hogy elkerülje a hivatkozásszám-ciklusokat, amelyek megakadályozhatják, hogy ezeket a vezérlőket a szemétgyűjtő valaha is visszanyerje.
Problémád van, ha...
- Ön a Win2D-t használja egy .NET nyelvről, mint például a C# (nem natív C++).
- A Win2D XAML-vezérlők egyikét használja:
- Feliratkozik a Win2D-vezérlő eseményeire (pl.
Draw,CreateResources,SizeChanged...) - Az alkalmazás egynél több XAML-oldal között mozog
Ha ezek a feltételek teljesülnek, a referenciaszám-ciklus megakadályozza, hogy a Win2D-vezérlő valaha is szemétgyűjtés alá kerüljön. Az új Win2D-erőforrások minden alkalommal ki vannak foglalva, amikor az alkalmazás egy másik oldalra kerül, de a régiek soha nem szabadulnak fel, így a memória kiszivárog. Ennek elkerülése érdekében kódot kell hozzáadnia a ciklus explicit megszakításához.
Javítási lehetőségek
Ha meg szeretné szakítani a hivatkozásszám ciklusát, és lehetővé szeretné tenni a lap szemétgyűjtését:
-
UnloadedA Win2D-vezérlőt tartalmazó XAML-oldal eseményének összekapcsolása -
UnloadedA kezelőben hívja megRemoveFromVisualTreea Win2D-vezérlőt - A
Unloadedkezelőben engedje el a Win2D-vezérlőre mutató explicit hivatkozásokat úgy, hogy azokat beállítjanull.
Példakód:
void page_Unloaded(object sender, RoutedEventArgs e)
{
this.canvas.RemoveFromVisualTree();
this.canvas = null;
}
A működő példákért tekintse meg a Mintagyűjtemény bemutatóoldalait.
Hogyan teszteljük a ciklusszivárgásokat
Annak ellenőrzéséhez, hogy az alkalmazás helyesen szakítja-e meg az újraszámlálási ciklusokat, adjon hozzá egy véglegesítő metódust a Win2D-vezérlőket tartalmazó XAML-lapokhoz:
~MyPage()
{
System.Diagnostics.Debug.WriteLine("~" + GetType().Name);
}
App A konstruktorban állítson be egy időzítőt, amely biztosítja, hogy a szemétgyűjtés rendszeres időközönként történjen:
var gcTimer = new DispatcherTimer();
gcTimer.Tick += (sender, e) => { GC.Collect(); };
gcTimer.Interval = TimeSpan.FromSeconds(1);
gcTimer.Start();
Nyissa meg az oldalt, majd lépjen át egy másik oldalra. Ha az összes ciklus megszakadt, a Debug.WriteLine kimenet egy-két másodpercen belül megjelenik a Visual Studio kimeneti paneljén.
Vegye figyelembe, hogy a hívás GC.Collect zavaró és rontja a teljesítményt, ezért azonnal távolítsa el ezt a tesztkódot, amint befejezi a szivárgások tesztelését!
A véres részletek
Ciklus akkor fordul elő, ha az A objektum a B-re hivatkozik, miközben B is az A-ra hivatkozik. Vagy ha az A hivatkozik a B-re, a B hivatkozik a C-re, míg a C hivatkozik az A-ra, stb.
Ha feliratkozik egy XAML-vezérlő eseményeire, ez a fajta ciklus nagyjából elkerülhetetlen:
- Az XAML-oldal a benne található összes vezérlőre hivatkozik
- A vezérlők az eseményeikhez kapcsolt kezelési delegáltakra mutató hivatkozásokat tartalmaznak.
- Minden meghatalmazott hivatkozik a célpéldányára
- Az eseménykezelők általában az XAML oldal osztály példánymetódusai, így a célpéldány-hivatkozások visszairányulnak az XAML oldalra, és létrehoznak egy ciklust.
Ha az összes érintett objektum a .NET-ben van implementálva, az ilyen ciklusok nem jelentenek problémát, mert a .NET szemétgyűjtésre kerül, és a szemétgyűjtési algoritmus akkor is képes azonosítani és visszaigényelni az objektumcsoportokat, ha azok egy ciklusban vannak összekapcsolva.
A .NET-tel ellentétben a C++ a memóriát hivatkozásszámlálással kezeli, amely nem képes észlelni és visszanyerni az objektumok ciklusait. A korlátozás ellenére a Win2D-t használó C++ alkalmazásoknak nincs gondjuk, mivel a C++ eseménykezelők alapértelmezés szerint gyenge, nem pedig erős hivatkozásokat tartalmaznak a célpéldányukra. Ezért a lap a vezérlőre hivatkozik, a vezérlő pedig az eseménykezelő delegáltjára, de ez a delegált nem hivatkozik vissza a lapra, így nincs ciklus.
A probléma akkor jelentkezik, ha egy .NET-alkalmazás egy C++ WinRT-összetevőt, például Win2D-t használ:
- Az XAML-oldal az alkalmazás része, ezért szemétgyűjtést használ
- A Win2D-vezérlő a C++-ban van implementálva, ezért hivatkozásszámlálást használ
- Az eseménykezelő delegáltja az alkalmazás része, ezért szemétgyűjtést használ, és erős hivatkozást tartalmaz a célpéldányra
Van egy ciklus, de a ciklusban részt vevő Win2D-objektumok nem .NET szemétgyűjtést használnak. Ez azt jelenti, hogy a szemétgyűjtő nem látja a teljes láncot, ezért nem tudja észlelni vagy visszanyerni az objektumokat. Ha ez történik, az alkalmazásnak segítenie kell a ciklus explicit megszakításával. Ezt úgy teheti meg, hogy a lapról a vezérlőre mutató összes hivatkozást felengedi (a fentieknek megfelelően), vagy az összes olyan hivatkozást felszabadítja a vezérlőből az eseménykezelő delegáltjai számára, amelyek a lapra mutathatnak (a lap kiürített eseményével leiratkozhat az összes eseménykezelőről).
Windows developer