Zabraná paměť

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, on-line

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?
25.1.2008 12:57:34

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.
25.1.2008 13:26:17

Hds:

Tohle by mě taky moc zajímalo...
25.1.2008 13:31:03

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.
25.1.2008 14:25:27

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?
27.1.2008 03:43:45

ikona v6ak:

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

ikona Jakub Hejda:

To neni zrovna elegantní řešení. to už je lepší použít irfan.
27.1.2008 16:59:46

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.
27.1.2008 17:58:37

ikona Jakub Hejda:

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

ikona v6ak:

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

Juraj:

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

ikona Jakub Vrána:

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é.
28.1.2008 11:14:04

Juraj:

Každý dobrý hosting však poskytuje GD a prípadne IMagick.
25.1.2008 23:20:22

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ěť.
25.1.2008 13:24:36

ikona Jakub Vrána:

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.
25.1.2008 13:28:43

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?
25.1.2008 14:12:31

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
25.1.2008 16:59:25

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.
30.1.2008 15:50:16

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...
31.1.2008 21:44:09

ikona Jakub Vrána:

Výsledky spuštění pod Linuxem jsem doplnil.
1.2.2008 11:37:26

ikona v6ak:

Na Linuxu naměřilo phpko stejně?
1.2.2008 12:36:53

ikona Jakub Vrána:

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

80
+0
+14564
–0
+0
+564
–14669
1.2.2008 17:59:54

ikona v6ak:

Já mluvím o měření z php, ne z OS.
1.2.2008 21:09:32

ikona Jakub Vrána:

Já taky ;-).
5.2.2008 11:34:46

ikona v6ak:

Tak to je fajn. Nebylo mi to úplně jasné.
7.2.2008 09:24:29

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...
1.2.2008 20:21:59

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é.
8.2.2008 11:03:45

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.
31.5.2008 12:49:00

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ášť.
1.6.2008 23:27:24

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 .
2.6.2008 10:01:50

ikona Jakub Vrána:

Dělá to funkce memory_get_peak_usage().
2.6.2008 12:59:52
avatar © 2005-2024 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.