Zabraná paměť

Školení, která pořádám

V PHP je k dispozici funkce memory_get_usage, která vrátí velikost zabrané paměti. Stejnou hodnotu používá i konfigurační direktiva memory_limit pro omezení maximálního množství paměti zabrané skriptem. Určitou paměť ale také zabírají knihovny, které PHP používá, tato funkce ji ale nezapočítává.

Pod Windows XP v PHP 5.2.5 a pod Linuxem s jádrem 2.6.20.4-grsec v PHP 5.2.0-8+etch7 jsem spustil následující jednoduchý skript a měřil jsem množství zabrané paměti podle PHP a celkem v operačním systému:

<?php
$tabulka = array();
$result = mysql_query("SELECT * FROM tabulka");
while ($row = mysql_fetch_assoc($result)) {
    $tabulka[] = $row;
}
mysql_free_result($result);
$kopie = $tabulka;
unset($kopie[0]);
unset($kopie, $tabulka);
?>
Okamžikpodle PHPpodle Windowspodle Linuxu
začátek61 kB11724 kB8484 kB
položení dotazu+0 kB+2256 kB+2568 kB
průchod cyklem+8665 kB+8512 kB+14052 kB
uvolnění dotazu–0 kB–2188 kB–2428 kB
zkopírování proměnné+0 kB+8 kB+4 kB
odnastavení prvku pole+305 kB+304 kB+564 kB
odnastavení proměnných–8905 kB–8188 kB–14144 kB

Datový soubor s tabulkou měl 2 MB. Je vidět, že už samotné položení dotazu stáhne data z databáze (na rozdíl od mysql_unbuffered_query), tato jsou ale uložena knihovnou. Následující uložení tabulky do pole zabere přes 8 MB paměti (ukládají se i klíče pole a něco také zabere organizace pole), jeho zkopírování do druhé proměnné nezabere nic. PHP totiž data kopíruje, až když to je potřeba. K tomu dojde při odnastavení prvního prvku druhého pole, které tím pádem paměť zabere, místo aby ji ušetřilo. Odnastavení obou proměnných vrátí skoro všechnu zabranou paměť.

Obvykle se o množství zabrané paměti není potřeba příliš starat, ale je dobré mít alespoň představu, kdy se kolik paměti zhruba zabírá.

Přijďte si o tomto tématu popovídat na školení Výkonnost webových aplikací.

Jakub Vrána, Ze zákulisí, 25.1.2008, diskuse: 31 (nové: 0)

Diskuse

Bohdan:

Neznáte nějaký způsob, jak zmenšit obrázek větších rozměrů, když to nejde přes gd kvůli malému memory_limitu a imagemagick není k dispozici? Pro většinu formátů je možné obrázek přímo dekomprimovat do menšího rozlišení, zmenšování by pak nezabralo tolik paměti. Vlastně zvažuji, že bych se do toho pustil, nějaké zmenšování uploadovaných obrázků je potřeba skoro všude.

Víte u nás o nějakém dobrém hostingu kde by to nebyl problém?

ATom:

No, tohle by mě taky zajímalo, gd knihovna celý obazek převede do bitmapy a to je při dnešních rorměrech uploadovaných fotek doslova katastrofa.

Hds:

Tohle by mě taky moc zajímalo...

Tom:

Jisteze, nepouzivejte bezne webhostingy ale pro tento web s rozsahlou galerii uzijte vlastni server. Pak nebudete mit problem tam mit spusteny s nizkou prioritou imagemagick, ktery vam je bude davkove zmensovat a s citelne nizsi reziji nez php.

Nick:

To je sice krasna rada, ale k nicemu. Zakaznik ma web o par strankach a do galerie chce obcas vlozit nejakou aktualni fotku. Jelikoz ma zrcadlo, tak o velikosti 3000*2000px. Nechce instalovat a ucit se ovladat zadne graficke programy. Proste fotka z fotaku nejkratsi cestou primo na web. A na webu to ma byt velke 1024*681px. Vlastni server neprichazi v uvahu (kdo to zaplati?). Hosting ma nastavene nizky memory_limit, protoze dle vyjadreni podpory "je nastaveny tak, aby vyhovoval naproste vetsine zakazniku". Kdo chce vetsi memory_limit, necht zaplati nepomerne vetsi pausal. Mate nejakou radu ted?

ikona v6ak:

Leda mu na komplu nainstalovat phpko a udělat nějaký baťák, který spustí php skript, který zmenší fotku...

ikona Jakub Hejda:

To neni zrovna elegantní řešení. to už je lepší použít irfan.

ikona v6ak:

Ono by to mělo nějak jít integrovat s průzkumníkem a pak je to sranda. Jen mu nesmí vadit to černé okénko.

ikona Jakub Hejda:

Stejně mi přijde nesmyslný instalovat klientovi na osobní počítač Apache server s PHP jen pro zmenšování fotek.

ikona v6ak:

Na co Apache? Stačí php spouštěné z komadnlajny...
BTW: Instalovat JRE nikomu divný nepřijde, je divné instalovat php?

Juraj:

Tak jedine použiť IMagick ten má menšie pamaťové nároky ako knižnica GD.

ikona Jakub Vrána OpenID:

Přenášet obrázek 3000x2000 bodů je nešikovné nejen kvůli zabrané paměti, ale i kvůli tomu, že to dlouho trvá. Pokud nechce žádný externí program, tak by asi byla ideální nějaká Flashová komponenta, která by to zmenšila u klienta a na server poslala už malé.

Juraj:

Každý dobrý hosting však poskytuje GD a prípadne IMagick.

ATom:

A odkud je přesně brány ten nárust paměti procesu? Přímo z procesu apache serveru (PHP) nebo z celkové dostupné paměti ve Windows?. Protože už při položení dotazu si podle mě bez ohledu na to, co dělá mysql_query() načte do cache ta data samotná MySQL a v systému klesne paměť.

ikona Jakub Vrána OpenID:

Skript jsem spouštěl z příkazové řádky, nikoliv přes Apache. Paměť zabranou MySQL jsem nezohledňoval, to může běžet na jiném serveru. Jde tedy o paměť zabranou procesem PHP.

Bohdan:

Takže pokud pameť zabírá nějaká knihovna, nedá se rozlišit jaký skript to má na svědomí? Tedy nejde ani omezit skutečnou velikost zabrané paměti na skript?

optik:

Nové rozhraní myslqnd, které by se mělo objevit snad už v php 5.3 by mělo práci s pamětí pro všechny mysql php moduly zefektivnit - viz http://mirin.cz/blog/co-znamena-mysqlnd

N. J.:

Mohl bys Havrane zase neco noveho napsat? Ja uz se docela nudim, na CZ/SK web scene je to samy sucker, proto nemam co cist.

Hannes:

bylo by asi zajimavejsi cely skript testovat na linuxu, server s php na windowsech (a jeste k tomu win xp) asi ze serioznich hostingu neprovozuje skoro nikdo...

ikona Jakub Vrána OpenID:

Výsledky spuštění pod Linuxem jsem doplnil.

ikona v6ak:

Na Linuxu naměřilo phpko stejně?

ikona Jakub Vrána OpenID:

Strukturou ano, v absolutních číslech o něco výš:

80
+0
+14564
–0
+0
+564
–14669

ikona v6ak:

Já mluvím o měření z php, ne z OS.

ikona Jakub Vrána OpenID:

Já taky ;-).

ikona v6ak:

Tak to je fajn. Nebylo mi to úplně jasné.

Malis:

Už mi bylo sice vysvětleno, že to nejde, ale přesto mi to nedá se nezeptat se i zde, bo je to tu samý expert:
Je mi jasné (a celkem pochopitelné), že nepřinutím skript zabrat více paměti, popř. běžet déle, než je povoleno. Nicméně bohatě by mi stačilo, kdyby se existovalo něco jako "ghost" funkce, která by mi řekla "Ne, ne, ne, tohle spadne, to zabere moc paměti".
A ještě lepší by bylo, kdyby funkce, která se blíží časovému limitu či vymezené paměti, uměla nějak efektně spadnout s nějakou chybovou návratovou hodnotou, se kterou by se dalo nějak rozumně pracovat. Ale to bych asi už chtěl moc.
Protože nevím, že by něco takového bylo, řeším to pomocí omezení, co vlastně program může zpracovávat a nechávám si dostatečnou rezervu. Kdybyste mě ale někdo vyvedl z omylu a prohlásil, že něco takového existuje, hned by na tom světě bylo růžověji...

Pavel Zbytovský:

Myslím, že žádná podobná funkce neexistuje, můžeš to leda zkusit odhadnout, kolik to bude zabírat.

Co se týče ukončení skriptu před vypršením max_timu, tak to takový problém není. Počítáš si čas pomocí microtime a v předpokladaných dlouhotrvajících cyklech si kontrolovat jestli se to neblíží. Zkuste se inspirovat v uploadovací funkci phpmyadmina.

A co se týče paměti, spočítat si kolik bude mít výsledek z databáze tak těžké není a jediný problém tedy je spočítat, kolik bude mít otevřený JPEG - doporučuji diskusi pod manuálovou stránkou: http://php.net/manual/en/function.imagecreatefromjpeg.php - je to tam několikrát a podle vlastní zkušenosti to je použitelné.

PHX:

Jde nejak zjistit kolik pameti dany script zabral maximalne? Jedine co me napada je, dat za kazdy prikaz svoji funkci, ale to je silene.

ikona v6ak:

PHP umí i větvení. AFAIK o tom bylo i na tomto webu. Pokud budeš zaznamenávat vše, musíš nějak odečíst paměť zabranou měřící fcí, která bude narůstat, nebo pokaždé např. otevřít, upravit a zavřít soubor. Pokud budeš uchovávat jen maxmum, mělo by to stačit.

Jen nevím, zda se každému vlánku neměří paměť zvlášť.

ikona v6ak:

Poté, co jsem si p sobě přečetl příspěvek doplním: větvením myslím multitasking: http://php.vrana.cz/paralelni-zpracovani.php .

ikona Jakub Vrána OpenID:

Dělá to funkce memory_get_peak_usage().

Vložit komentář

Používejte diakritiku. Vstup se chápe jako čistý text, ale URL budou převedeny na odkazy a PHP kód uzavřený do <?php ?> bude zvýrazněn. Pokud máte dotaz, který nesouvisí s článkem, zkuste raději diskusi o PHP, zde se odpovědi pravděpodobně nedočkáte.

Jméno: URL:

avatar © 2005-2018 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení Creative Commons. Můžeme si tykat. Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset. Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.