LINUXSOFT.cz Přeskoč levou lištu

ARCHIV



   

> C++ a garbage collector

Často se mluví o tom, že C++ nemá garbage collector. Jenže ona to, přísně vzato, není ani trochu pravda. Už mnoho let tvrdím, že kdo v C++ ručně uvolňuje paměť a zavírá různé zdroje, ten neumí C++. Tento článek filozofuje s otázkou, zda C++ má či nemá garbage collector.

11.8.2014 19:00 | Miloslav Ponkrác | Články autora | přečteno 23479×

1. C++ a garbage collector

1.1. C++ není C s třídami

Jedna z nejhorších věcí, které může člověk dělat je, že chce předělávat jazyk či knihovnu k obrazu svému do cizí filozofie. Řada lidí posuzuje C++ jako C s třídami a přisuzují mu tytéž vlastnosti jako jazyku C. Jistě, že v C++ se dá programovat C stylem, ale je to obrovská škoda, protože C++ nabízí mnohem mnohem více. Využít možnosti C++ znamená v první řadě zapomenout C styl a nedělat věci v C++ tak, jak by je člověk dělal v C.

Pokud programujete v C++, využívejte jeho možností. C++ je velmi efektivní jazyk, umožňující mnohem efektivnější a rychlejší vývoj, než v C, aniž byste ztratili jedinou výhodu proti jazyku C. V C++ lze napsat program mnohem rychleji a efektivněji, než v C, přitom výsledek bude mnohem lépe udržovatelnější zdrojový kód oproti C a výsledná binárka bude stejně rychlá jako kdyby byla napsána v C. Abyste tohoto dosáhli, je třeba využívat možností a vlastností C++. Kdokoli má pocit, že C++ je pouze C s třídami, neříká tím o sobě nic jiného, než „já neumím C++“.

1.2. Cíle článku

V tomto článku se pokusím jednoduše zodpovědět na 3 otázky:

  1. Má C++ garbage collector pro automatické uklízení paměti?

  2. Potřebuje C++ garbage collector?

  3. Je účelné vybavit C++ garbage collectorem?

2. Má C++ garbage collector pro automatické uklízení paměti?

Správná odpověď je: Přijde na to.

C++ umožňuje vytvářet pointery, které jsou plně na zodpovědnosti programátora. A které programátor uklízí ručně a plně na své triko.

C++ umožňuje vytvářet pointery i objekty, které se automaticky dealokují a uklízejí bez starosti programátora.

Takže na otázku „Je pravdou, že C++ nemá garbage collector?“, nelze poctivě odpovědět, že C++ nemá garbage collector.

2.1. Návrhový vzor RAII

Programovací jazyk C++ pracuje na principu, že samotný C++ kompilátor velmi masivně už na úrovni jazyka C++ podporuje objektový návrhový vzor RAII (Resource Acquistion Is Initialization), nazývaný také SBRM (Scope Based Resource Management). Tento objektový návrhový vzor řídí životnost objektů, proto patří to do skupiny „creational patterns“.

Ve své podstatě je to vlastně „cé plus plus kovina“, protože je v ní cítit přesně ideologie C++. Tedy zobecňování principů až do maximální rozsahu, působení a důsledků, jaký je možný.

Dokonce právě uvědomění si základní vlastnosti programovacího jazyka C++, tedy, že se skládá v zásadě z několika jednoduchých základních principů a vlastností, které jsou dotáhnuté až do maxima, považuji za nejlepší způsob, jak se bezbolestně naučit C++. Pokud v C++ platí nějaký princip či vlastnost, pak pokud možno platí všude, na všechny typy i programátorské konsktrukce, kde je to jen trochu možné. Té vlastnosti říkám „cé plus plus kovina“, tedy obrovská vnitřní konzistence, logičnost a jednotnost celého C++ jazyka. Učit se C++ jinak, než pochopením jeho principů je velmi složité, učit se C++ pochopením jeho principů je velmi jednoduché a rychlé.

2.2. C++ dotahuje princip uklízení lokálních proměnných do absolutní dokonalosti

Člověk očekává, že ukončením podprogramu (či bloku programu) se automaticky odstraní a uklidí i lokální proměnné bez starostí programátora. Toto je ovšem ve většině programovacích jazyků nedotáhnuté, a není tomu plně tak. Vezmete-li si třeba Javu, .NET, C a mnoha dalších jazyků, nemůžete od nich očekávat to, že kompilátor zařídí také plný úklid lokálních proměnných. Uklízí se bez problémů proměnné typu integer, ale ne objekty. C++ dotáhl uklízení lokálních proměnných na plný automatický úklid a to pro jakékoli proměnné jakéhokoli typu. Tohle dotahování do konce je vlastně to, čemu říkám „cé plus plus kovina“, protože takto vzniklo skoro celé C++. Dotáhnutím principů do konce bez výjimek a nedotažeností.

Zaručený automatický úklid všech lokálních proměnných se právě nazývá RAII. Jednoduše stačí získat zdroj (paměť, soubor, grafický handle, cokoli) a uložit ho do proměnné, která ho bude vlastnit a při jejím zániku (voláním destruktoru) ho také uvolní. A tím se o to můžete přestat starat, protože zbytek zařídí C++ kompilátor, který bude uvolňovat zdroje automaticky v rámci rušení lokálních proměnných na konci oboru platnosti. A tomu se vznešeně říká RAII.

2.3. RAII versus klasický garbage collector

Ačkoli to vypadá jako nic moc, RAII je skutečně velmi dobrý garbage collector. Dokonce má další výhody:

  1. RAII uklízí nejenom paměť, ale všechny zdroje (třeba otevřené handly souborů, grafických prvků, síťové sokety, …).

  2. RAII je voláno okamžitě bez prodlení a přesně v čase, kdy zdroj přestává být potřeba.

  3. Proměnné a zdroje likviduje po skončení platnosti stejný thread jako jim dal vzniknout.

  4. Není třeba zastavovat program kvůli garbage collectoru jako v Javě, LISPu, a dalších.

Má samozřejmě i nevýhody:

  1. Je nepatrně pomalejší, protože RAII dealokuje okamžitě jedno po druhém, zatímco klasické garbage collectory dealokují naráz velké množství bloků paměti.

  2. Je třeba věnovat podpoře RAII pozornost při implementaci tříd.

2.4. C++ a uklízení sdílených proměnných

Dobrá, RAII tedy zruší již nepoužívanou paměť a zdroje lokálních proměnných. Ale co tedy uklízení paměti a zdrojů sdílených více tready nebo vranými jako návratové hodnoty?

Budete se divit, toto RAII také zvládne. Protože všechny případy automatického uklízení paměti se dají převést na uklízení lokálních proměnných. Kdy je třeba paměťový blok dealokovat? Když pointer na tento blok není obsažen v žádné proměnné, míněno v žádné lokální proměnné. Jakmile neexistuje lokální proměnná, která obsahuje adresu nějakého paměťového bloku, pak je třeba tento blok uklidit. A toto je možné pomocí RAII zařídit.

Nicméně zde je třeba použít chytré pointery z C++ standardní knihovny nebo podobnou funkcionalitu. Například std::auto_ptr nebo std::shared_ptr. Případně si napsat vlastní třídy.

Není tedy problém mít (jde o myšlenkový nástin, skutečný kód by byl odlišný):

MojeTrida * JinaTrida::getInfo()
{
  …
};

int main()
{
  JinaTrida a;
  a.getInfo();
  int x = a.getInfo()->getXParameter();
  MojeTrida * info = a.getInfo();
  int y = info->getYParameter();
  return 0;
};

A ačkoli se o to nestaráte, ve funkci main() nevznikne žádný memory leak, všechna paměť se uklidí a všechny instance třídy MojeTrida, které jsou vráceny metodou getInfo() budou automaticky uklizeny hned jak nebudou potřeba.

Jinak řečeno, v C++ opravdu je možné vracet z funkcí a metod pointery na objekty, a nechat C++ jejich automatické uklízení, aniž byste se o uklízení starali ručně.

2.5. C++ a garbage collecting

Znovu se ptám: „Má nebo nemá C++ garbage collector?“ Jak vidíte, odpovědět jde opravdu těžko. Oficiálně nemá, prakticky ale obsahuje věkerou funkčnost garbage collectoru, když o to budete stát a budete to potřebovat.

Už 10 let tvrdím, že pokud se v C++ někdo musí starat ručně o uvolňování paměti, tak neprogramuje v C++, protože ho neumí.

3. Potřebuje C++ klasický garbage collector?

V každém jazyce je dobré mít možnost garbage collectoru, jde-li to. Garbage collector je příjemná feature.

Na druhé straně garbage collector nemá jenom plusy.

3.1. Klasický garbage collector

Garbage collectorů je mnoho druhů, klasický garbage collector funguje na principu procházení všech identifikátorů v programu a uklízí pak ty bloky paměti, na které nevede žádný odkaz. A zde je kámen úrazu. Těžko bude garbage collector zjišťovat a procházet identifikátor, když program běží a identifikátory mění své hodnoty, protože programu musí stát a násilně být zastaven. A to se velmi často nehodí, přesněji, nehodí se to skoro nikdy. Pokud program dělá rychlostně kritickou činnost, pak garbage collector na chvíli zastavující program je poslední ranou do vazu. Ale i jinak, uživatel není rád, když program sekundu nereaguji na jeho kliknutí na tlačítko, protože zrovna se probral gc. To se různě eliminuje, ale je to jen zmírnění problému, nikoli jeho odstranění:

  1. Část práce se udělá za běhu programu inkrementálně.

  2. Paměťové bloky se rozdělí za několik generací, přičemž v nulté generaci jsou lokální proměnné, které se čistí okamžitě po skončení každého bloku. První a další generace pak chce už spuštění plnohodnotného gc.

  3. Opuletně se plýtvá s pamětí a gc se nespouští a nechává klidně hodiny i dny nevyčištěnou paměť v množství klidně stovek MB i několik GB.

  4. Jazyk má API, které umožňuje zakázat spuštění gc pro kritické fáze, nebo naopak doporučit spuštění gc, pokud je času dostatek.

Toto nejsou všechny problémy klasického gc. Další problém je uvolňování zdrojů. Gc se postará o uvolňování paměti, ale už ne dalších zdrojů. Programátor se o to musí starat ručně, pokud nemá docházet k plýtvání zdroji. A tak se to zase řeší nalepováky:

  1. Metody typu finalize().

  2. Metody typu dispose() v .NET.

3.2. Garbage collector typu čítač referencí

Cílem článku není kritizovat klasický garbage collector. Existují i gc, které uvolňují okamžitě a většinu výhod výše eliminují. Například čítač odkazů. Jenže ten má další nevýhody:

  1. Paměťová náročnost. Každá proměnné a každý blok má navíc 4 bajty na čítač odkazů. Dohromady je to obrovská paměťová náročnost.

  2. Problém s cyklickými odkazy, které nedokáže čítač referencí odhalit.

3.3. C++ a potřeba garbage collectoru

C++ jednoduše takové garbage collectory opravdu nepotřebuje. Jednoduše proto, že oblast používání C++ je tam, kde by vlastnosti klasického garbage collectoru či čítače referencí zničily to, co od C++ je žádáno.

Namísto toho proto C++ integrovalo RAII, které udělalo přesně to, co je třeba:

  1. Namísto procházení identifikátory a zjišťování seznamů nepotřebných bloků za běhu programu se všechno toto zařídí ve fázi kompilace programu. C++ kompilátor sám podle oboru platnosti lokálních proměnných vytvoří seznam už v době kompilace včetně automaticky generovaného kódu pro úklid paměti i zdrojů. Tím se neplýtvá cenným časem za běhu programu, stejně tak jako odpadá požadavek aby program měl přehled o všech proměnných za běhu programu.

  2. Namísto čítače referencí C++ kompilátor jednoduše detekuje místa už v době kompilace, kde má dojít k úklidu.

4. Je účelné vybavit C++ garbage collectorem?

Tato otázka už je mírně nadbytečná.

C++ má už v samotném jazyce vše potřebné pro automatické uklízení paměti a zdrojů v podpoře RAII. Jako vždy, C++ pouze nabízí, ale nevnucuje. Můžete klidně dělat program, kde budete celý životní cyklus paměti i zdrojů řídit sami, stejně jako můžete udělat program, kde uklízení bude probíhat zcela automaticky.


Článek daroval: Ing. Miloslav Ponkrác
www.ponkrac.net

Verze pro tisk

pridej.cz

 

DISKUZE

To je hlod 27.8.2014 11:19 Jan Němec
L Re: To je hlod 5.9.2014 15:18 Miloslav Ponkrác
  L Re: To je hlod 8.9.2014 11:28 Jan Němec
    |- Re: To je hlod 8.9.2014 16:26 Miloslav Ponkrác
    | L Re: To je hlod 22.9.2014 08:35 Aleš Hakl
    |   L Re: To je hlod 25.9.2014 03:11 Miloslav Ponkrác
    L Re: To je hlod 8.9.2014 16:29 Miloslav Ponkrác
      L Re: To je hlod 29.9.2014 15:35 Jan Němec
        L Re: To je hlod 1.10.2014 00:26 Miloslav Ponkrác
Díky za článek 4.9.2014 14:14 František Kučera
  L Re: Díky za článek 5.9.2014 15:34 Miloslav Ponkrác
    L Re: Díky za článek 9.9.2014 15:58 František Kučera




Příspívat do diskuze mohou pouze registrovaní uživatelé.
> Vyhledávání software
> Vyhledávání článků

28.11.2018 23:56 /František Kučera
Prosincový sraz spolku OpenAlt se koná ve středu 5.12.2018 od 16:00 na adrese Zikova 1903/4, Praha 6. Tentokrát navštívíme organizaci CESNET. Na programu jsou dvě přednášky: Distribuované úložiště Ceph (Michal Strnad) a Plně šifrovaný disk na moderním systému (Ondřej Caletka). Následně se přesuneme do některé z nedalekých restaurací, kde budeme pokračovat v diskusi.
Komentářů: 1

12.11.2018 21:28 /Redakce Linuxsoft.cz
22. listopadu 2018 se koná v Praze na Karlově náměstí již pátý ročník konference s tématem Datová centra pro business, která nabídne odpovědi na aktuální a často řešené otázky: Jaké jsou aktuální trendy v oblasti datových center a jak je optimálně využít pro vlastní prospěch? Jak si zajistit odpovídající služby datových center? Podle jakých kritérií vybírat dodavatele služeb? Jak volit vhodné součásti infrastruktury při budování či rozšiřování vlastního datového centra? Jak efektivně datové centrum spravovat? Jak co nejlépe eliminovat možná rizika? apod. Příznivci LinuxSoftu mohou při registraci uplatnit kód LIN350, který jim přinese zvýhodněné vstupné s 50% slevou.
Přidat komentář

6.11.2018 2:04 /František Kučera
Říjnový pražský sraz spolku OpenAlt se koná v listopadu – již tento čtvrtek – 8. 11. 2018 od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Tentokrát bez oficiální přednášky, ale zato s dobrým jídlem a pivem – volná diskuse na téma umění a technologie, IoT, CNC, svobodný software, hardware a další hračky.
Přidat komentář

4.10.2018 21:30 /Ondřej Čečák
LinuxDays 2018 již tento víkend, registrace je otevřená.
Přidat komentář

18.9.2018 23:30 /František Kučera
Zářijový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 20. 9. 2018 od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Tentokrát bez oficiální přednášky, ale zato s dobrým jídlem a pivem – volná diskuse na téma IoT, CNC, svobodný software, hardware a další hračky.
Přidat komentář

9.9.2018 14:15 /Redakce Linuxsoft.cz
20.9.2018 proběhne v pražském Kongresovém centru Vavruška konference Mobilní řešení pro business. Návštěvníci si vyslechnou mimo jiné přednášky na témata: Nejdůležitější aktuální trendy v oblasti mobilních technologií, správa a zabezpečení mobilních zařízení ve firmách, jak mobilně přistupovat k informačnímu systému firmy, kdy se vyplatí používat odolná mobilní zařízení nebo jak zabezpečit mobilní komunikaci.
Přidat komentář

12.8.2018 16:58 /František Kučera
Srpnový pražský sraz spolku OpenAlt se koná ve čtvrtek – 16. 8. 2018 od 19:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát jsou tématem srazu databáze prezentaci svého projektu si pro nás připravil Standa Dzik. Dále bude prostor, abychom probrali nápady na využití IoT a sítě The Things Network, případně další témata.
Přidat komentář

16.7.2018 1:05 /František Kučera
Červencový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 19. 7. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát bude přednáška na téma: automatizační nástroj Ansible, kterou si připravil Martin Vicián.
Přidat komentář

   Více ...   Přidat zprávičku

> Poslední diskuze

31.7.2023 14:13 / Linda Graham
iPhone Services

30.11.2022 9:32 / Kyle McDermott
Hosting download unavailable

13.12.2018 10:57 / Jan Mareš
Re: zavináč

2.12.2018 23:56 / František Kučera
Sraz

5.10.2018 17:12 / Jakub Kuljovsky
Re: Jaký kurz a software by jste doporučili pro začínajcího kodéra?

Více ...

ISSN 1801-3805 | Provozovatel: Pavel Kysilka, IČ: 72868490 (2003-2024) | mail at linuxsoft dot cz | Design: www.megadesign.cz | Textová verze