LINUXSOFT.cz Přeskoč levou lištu
Uživatel: Heslo:  
   CZUKPL

> 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 18903×

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ů

18.6.2018 0:43 /František Kučera

Červnový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 21. 6. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát na téma: F-Droid, aneb svobodný software do vašeho mobilu. Kromě toho budou k vidění i vývojové desky HiFive1 se svobodným/otevřeným čipem RISC-V.


Přidat komentář

23.5.2018 20:55 /Ondřej Čečák
Od pátku 25.5. proběhne na Fakultě informačních technologií ČVUT v Praze openSUSE Conference. Můžete se těšit na spostu zajímavých přednášek, workshopů a také na Release Party nového openSUSE leap 15.0. V na stejném místě proběhne v sobotu 26.5. i seminář o bezpečnosti CryptoFest.
Přidat komentář

20.5.2018 17:45 /Redakce Linuxsoft.cz
Ve čtvrtek 31. května 2018 připravuje webový magazín BusinessIT ve spolupráci s Best Online Média s.r.o. pátý ročník odborné konference Firemní informační systémy 2018. Akce proběhne v kongresovém centru Vavruška (palác Charitas), Karlovo náměstí 5, Praha 2 (u metra Karlovo náměstí) od 9:00 hod. dopoledne do cca 15 hod. odpoledne. Konference je zaměřena na efektivní využití firemních informačních systémů a na to, jak plně využít jejich potenciál. Podrobnější informace na webových stránkách konfrence.
Přidat komentář

14.5.2018 7:28 /František Kučera
Květnový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 17. 5. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát na téma: Audio – zvuk v GNU/Linuxu.
Přidat komentář

7.5.2018 16:20 /František Kučera
Na stránkách spolku OpenAlt vyšla fotoreportáž Pražské srazy 2017 dokumentující srazy za uplynulý rok. Květnový pražský sraz na téma audio se bude konat 17. 5. 2018 (místo a čas ještě upřesníme).
Přidat komentář

17.4.2018 0:46 /František Kučera
Dubnový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 19. 4. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tématem tohoto srazu bude OpenStreetMap (OSM) aneb svobodné mapy.
Přidat komentář

16.3.2018 22:01 /František Kučera
Kulatý OpenAlt sraz v Praze oslavíme klasicky: u limonády a piva! Přijďte si posedět, dát si dobré jídlo a vybrat z mnoha piv do restaurace Kulový blesk, který najdete v centru Prahy nedaleko metra I. P. Pavlova na adrese Sokolská 13, Praha 2. Sraz se koná ve čtvrtek 22. března a začínáme v 18:00. Heslo: OpenAlt. Vezměte s sebou svoje hračky! Uvítáme, když si s sebou na sraz vezmete svoje oblíbené hračky. Jestli máte nějaký drobný projekt postavený na Arduinu, nějakou zajímavou elektronickou součástku, či třeba i pěkný úlovek z crowdfundingové akce, neváhejte. Oslníte ostatní a o zábavu bude postaráno.
Přidat komentář

13.2.2018 0:41 /František Kučera
Únorový pražský sraz OpenAltu se koná 15. 2. 2018 a tentokrát se vydáme na návštěvu do jednoho pražského datacentra. Sejdeme se v 17:50 v severovýchodní části nástupiště tramvajové zastávky Koh-I-Noor. Po exkurzi se přesuneme do restaurace U Pštrosa (Moskevská 49), kde probereme tradiční témata (svobodný software a hardware, DIY, CNC, SDR, 3D tisk…) a tentokrát bude k vidění i IoT brána od The Things Network.
Přidat komentář

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

> Poslední diskuze

20.2.2018 18:48 / Ivan Majer
portal

20.2.2018 15:57 / Jan Havel
Jak využíváte služby cloudu v podnikání?

16.1.2018 1:08 / Ivan Pittner
verejna ip od o2 ubuntu

15.1.2018 17:26 / Mira Harvalik
Re: Jak udělat HTML/Javascript swiping gallery do mobilu?

30.12.2017 20:16 / Michal Knoll
odmocnina

Více ...

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