Hlavní navigace

Jak (ne)optimalizovat spotřebu paměti v .NET

13. 12. 2011 23:13 zboj

Dnes jen krátce a ke konkrétnímu tématu. Jak známo, velké objekty GC na haldě nepřesouvá, takže pokud si je budete alokovat a uvolňovat sami, nezpůsobíte svým počínáním větší fragmentaci než GC. Právě velké objekty je vhodné uvolnit co nejdříve a pokud možno deterministicky. To není v .NET problém, na neřízené haldě lze alokovat třeba i sto MB a díky IDisposable paměť uvolnit, jakmile objekt nepotřebujeme. Můžeme mít tedy ve třídě nějaký pointer:

private: Neco* ptr;

Ten alokujeme v konstruktoru a uvolňujeme v destruktoru, tedy Dispose:

~Trida() { delete ptr; ptr = nullptr; }

Potíže nastanou, pokud nedisciplinovaný programátor objekt explicitně nezruší. Na první pohled vhodné řešení s finalizérem může být fatální:

!Trida() { delete ptr; }

Tím sice teoreticky zamezíme únikům paměti, jenže GC na neřízenou haldu zvysoka, ehm, kašle, takže dříve než úklidu se dočkáte výjimky OutOfMemoryException. Mnohem lepší je vyhodit ve finalizéru výjimku:

!Trida() { throw gcnew Exception("Object not disposed properly"); }

Nezlikvidovat náležitě objekt je pochopitelně chyba programátora, ale pořád se najdou jedinci, kteří nečtou dokumentaci, případně v životě neslyšeli o using, takže naservírováním výjimky, která s přehledem odstřelí celou aplikaci, jim vlastně děláte laskavost.