Java týden Java týden
Pouze tento týden sleva až 80 % na celý Java e-learning!
Brno? Vypsali jsme pro vás nové termíny školení OOP v Brně!

Diskuze: Boj s pamětí v PHP

Aktivity (2)
Avatar
Jan Poláček
Redaktor
Avatar
Jan Poláček:23. dubna 18:00

Ahoj, mám zadání vytvořit zálohu, bohužel jim nestačí DB export, ale chtějí to do čitelné podoby a to klienti a jejich záznamy, říkám si OK, pro každého klienta udělám přes mPDF PDF s jeho záznamy, zabalím do ZIPu a nechám stáhnout, bohužel mě trápí

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 6807788 bytes) in /volume1/web/mf/mpdf.php on line 30620

Zkusil jsem: Nejdříve jsem to měl na férovku, vytvořil jsem si ZIP a do něho postupně šoupal PDFka a pak zavřel, pak mě napadlo, OK, snažím se šetřit pamětí, nevím, zda to má vliv, ale vytvořil jsem ZIP, zavřel a pak otevřel pokaždé, jen když jsem vytvořil ve smyčce PDF a opět zavřel a zároveň i mazal původní PDF, nakonec jsem ještě uvažoval způsobem nějak zabít instanci mPDF a to že jsem jí nastavil null a ještě jsem zkusil unset, co by mohla zabírat místo v paměti, no nevím, radši dám kousek kódu.

include("mf/mpdf.php");
                Db::insert("archivace",array("od"=>$_POST["od"],"do"=>$_POST["do"],"sluzba"=>$_POST["sluzba"],"ida"=>$_SESSION["ida"]));//vložení do archivace
                $start = time();
                $zipname = "upload/zaloha/".$zkr[$_POST["sluzba"]].'/'.$_POST["od"].'_'.$_POST["do"].'.zip';//jméno ZIP souboru
                $zip = new ZipArchive;
                $zip->open($zipname, ZipArchive::CREATE);//VYTVOŘENÍ ZIP SOUBORU
                $zip->addFromString('test.txt', 'file content goes here');
                $zip->close();
$uzivatele = Db::queryAll("SELECT * FROM sas_uzivatel2 WHERE id IN (SELECT DISTINCT(idk) FROM sas_prubeh_sluzby2 WHERE datum>=? AND datum<=?)",$_POST["od"],$_POST["do"]);
                        foreach($uzivatele as $uz)//jedu uživatele
                        {
$cesta="upload/zaloha/pdf/";
                                $file=$uz["prijmeni"]."_".$uz["jmeno"]."_".$uz["narozeni"].".pdf";
                                $mpdf=new mPDF('',    // mode - default ''
                                         '',    // format - A4, for example, default ''
                                         11,     // font size - default 0
                                         '',    // default font family
                                         15,    // margin_left
                                         15,    // margin right
                                         10,     // margin top
                                         10,    // margin bottom
                                         9,     // margin header
                                         9,     // margin footer
                                         'L');  // L - landscape, P - portrait
                                //$mpdf->debug = true;
                                //$mpdf->showImageErrors = true;
                                $mpdf->WriteHTML($prubeh);
                                $mpdf->Output($cesta.$file,"F");
                                $mpdf=null;
                                unset($mpdf);
                                $zip = new ZipArchive;
                                $zip->open($zipname);
                                $zip->addFile($cesta.$file,$file);
                                $zip->close();

                                unlink($cesta.$file);
                        }

Chci docílit: Snažím se, aby skript doběhnul bez fyzické navýšení paměti, k tomu nemám přístup. Díky.

Odpovědět 23. dubna 18:00
Instrukce na adrese 0x77104f29 odkazovala na adresu paměti 0x00000014. S pamětí nelze provést operaci: written.
Avatar
Odpovídá na Jan Poláček
Tomáš Novotný:23. dubna 18:57

Ahoj,
tak otázka také je, kdy tu chybu dostaneš,,, zda-li už při include... nebo později.
Proč třeba nezabalíš soubory najednou a neoddělíš to od jejich generování?
Předpokládám, že by se ti to pak lépe odlaďovalo ...
Z kódu není třeba patrná velikost proměnné $prubeh ...
takže bych zkusil nejdříve pouze vygenerovat všechna PDFka... pokud to projde.. tak po vygenerování všechna zabalit, pokud to nepůjde tak po jednom třeba podle idk...

Editováno 23. dubna 18:57
Nahoru Odpovědět 23. dubna 18:57
∞ ... the exact amount of possibilities how to deal with the situation ... so by calm, your solution is one of many
Avatar
David Hynek
Redaktor
Avatar
Odpovídá na Jan Poláček
David Hynek:23. dubna 20:45

na radku 30 tisic? to je tedy velky program...

Nahoru Odpovědět 23. dubna 20:45
Čím víc vím, tím víc věcí nevím.
Avatar
David Hynek
Redaktor
Avatar
Odpovídá na Jan Poláček
David Hynek:23. dubna 20:49
$mpdf->WriteHTML($prubeh);

nezabere tohle reseni 2x tolik pameti co zabere sama promenna prubeh?

Nahoru Odpovědět 23. dubna 20:49
Čím víc vím, tím víc věcí nevím.
Avatar
Peter Mlich
Člen
Avatar
Odpovídá na Jan Poláček
Peter Mlich:24. dubna 8:00

Pozn.: Bylo by fajn, kdyby odpovedet fungovalo jako odkaz, s moznosti pres prave tlac. otevrit v novem okne. Vlevo bych mel okno se zadanim, vpravo okno s okenkem pro odpoved.

1) ini_set('memory_limit', '512'); // na zacatku programu si zmen limit, nebo v .htaccess nebo php.ini memory_limit = 256M, php_value memory_limit 256M
  1. Snaz se vse, co nepotrebujes, zahodit. unset() ...

$zip->close(); // ok
$mpdf=null; // ok
unset($mpdf); // ok
$zip->close(); // ok
Nelibi se mi tam to mpdf. Tam by to chtelo zkouknout kod. Nejspis duplikuje spoustu veci. A nebo proste pocitej s tim, ze budes potrebovat trochu vic pameti. Ostatne, tomu by odpovidala i ta chybova hlaska. Pamet dosla, kdyz vykonaval prikaz na radku...
/volume1/web/mf/m­pdf.php on line 30620
Mrkni, co tam je a pripadne to nech cele zkouknout, kdy to zabere kolik pameti.
function m($name='') {echo $name.' '.memory_get_u­sage().'
';}
a na zacatku kazde funkce dej m() nebo m('jmeno funkce')
Pripadne to vyresit nejak elegantne pres classy se da pridat neco, co se pusti jeste pred funkci, tusim. Pouziva to tusim nette pro lepsi vypis chyb. Ja nic takoveho nepouzil, zatim a ani v tom nevidim prinos, prilis.

  1. A nemas tam jeste nejaky dalsi kod, ktery ti zabira pamet?

4)
"SELECT * FROM sas_uzivatel2 WHERE id IN (SELECT DISTINCT(idk) FROM sas_prubeh_sluzby2 WHERE datum>=? AND datum<=?)"
Jak dlouho sql provadi jen tento samotny dotaz? A Koli mu to veme pameti? Neslo by to napsat logicteji, treba opacne?
SELECT DISTINCT(idk) FROM sas_prubeh_sluzby2 LEFT JOIN uzivatele... WHERE datum>=? AND datum<=?

 
Nahoru Odpovědět 24. dubna 8:00
Avatar
Jan Poláček
Redaktor
Avatar
Odpovídá na David Hynek
Jan Poláček:24. dubna 12:43

Ano, mPDF je velká knihovna pro tvorbu PDF souborů, ale obyčejná tvorba bez toho je pro mě za trest - pozicování každého prvku (x,y), takto schroupe html a hotovo.

Nahoru Odpovědět 24. dubna 12:43
Instrukce na adrese 0x77104f29 odkazovala na adresu paměti 0x00000014. S pamětí nelze provést operaci: written.
Avatar
Jan Poláček
Redaktor
Avatar
Odpovídá na Tomáš Novotný
Jan Poláček:24. dubna 12:46

Chyba nastane cca v půlce, dejme tomu po 30 minutách běhu, zkusím tedy vygenerovat všechny PDF, zda to projde a pak celou složku zabalit, zatím díky.

Nahoru Odpovědět 24. dubna 12:46
Instrukce na adrese 0x77104f29 odkazovala na adresu paměti 0x00000014. S pamětí nelze provést operaci: written.
Avatar
Jan Poláček
Redaktor
Avatar
Odpovídá na Peter Mlich
Jan Poláček:24. dubna 13:01

Ahoj, bohužel nemohu změnit limit paměti, do ini nemám přístup a změna v htaccess není povolena a ani v samotném skriptu, zkusím to zkoumat přes memory_get_usage(), tak uvidíme,, zatím děkuji.

Nahoru Odpovědět 24. dubna 13:01
Instrukce na adrese 0x77104f29 odkazovala na adresu paměti 0x00000014. S pamětí nelze provést operaci: written.
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:24. dubna 15:41

Tak jiny pdf generator.
A ty predchozi pdf jsou spravne?
A v kodu neni ani z ceho ziskavas $prubeh? Jestli treba nezapisuje nahodny retezec z pameti nebo tam nemas nekde scitani. $prubeh.=neco;

Jo, a jak pise Hynek, mozna se v te funkci duplikuje promena, ikdyz nic takoveho nepotrebujes.
$mpdf->WriteHTML($pru­beh);
... function WriteHTML($prubeh);
... function WriteHTML(&$pru­beh); // preda pointer - to by mohlo byt pomalejsi, ale uspornejsi na pamet

unlink($cesta­.$file);
nejdriv to ulozis a pak soubor smazes? :)

Editováno 24. dubna 15:42
 
Nahoru Odpovědět 24. dubna 15:41
Avatar
Jan Poláček
Redaktor
Avatar
Odpovídá na Peter Mlich
Jan Poláček:24. dubna 15:49

Ano, to bych se mohl podívat
Vše je správně, uloží se mi do zipu přes 20 funkčních pdf souborů
$prubeh získávám z dalšího dotazu DB, tzn., nejdřív se ptám:
ukaž mi všechny uživatele mající zápis v zadaném období (* v dotazu z důvodu, že ty informace o uživateli zapisuju také do pdf)
a další dotaz je:
ukaž mi všechny záznamy daného uživatele
to vše postupně ukládám do proměnné $prubeh a pak předám mPDF, ale $prubeh se mi nezvětšuje, protože na začátku dalšího uživatele opět $prubeh přepíšu novými daty dalšího uživatele
mohu to zkusit s tím pointerem
co se týče unlink, tak původní soubor mohu smazat, když už ho mám v tom zipu :)

Nahoru Odpovědět 24. dubna 15:49
Instrukce na adrese 0x77104f29 odkazovala na adresu paměti 0x00000014. S pamětí nelze provést operaci: written.
Avatar
Odpovídá na Jan Poláček
Tomáš Novotný:24. dubna 23:22

Přijde mi trochu zvláštní tento kontext...

include("mf/mpdf.php");
....
foreach($uzivatele as $uz)//jedu uživatele
{
...
$mpdf->WriteHTML($prubeh);
...
}

Není mi jasné zda to prochází jednoho uživatele nebo několik uživatelů?
Pokud jednoho uzivatele - proč je tam foreach?
Pokud několik, jak to, že se nemění $prubeh? Ani nemá index. Tj. ke všem uživatelům se vloží stejný obsah.
Pokud se $prubeh mění podle uživatele mimo zde uveřejněný kód a následně se tento výše uvedený spouští, nerozumím tedy neustálému include a foreach...

Editováno 24. dubna 23:23
Nahoru Odpovědět 24. dubna 23:22
∞ ... the exact amount of possibilities how to deal with the situation ... so by calm, your solution is one of many
Avatar
Peter Mlich
Člen
Avatar
Odpovídá na Tomáš Novotný
Peter Mlich:25. dubna 7:24

Jo, to prave napsal, ze nas osidil a dulezitou cast kodu a napsal jen tu, co si myslim, ze je v ni problem. A v ni zrovna asi problem neni.

https://www.php.net/…icrotime.php
Zkus upravit ten example1 tak, aby vypsal cas a schvalne zkus vypis casu pred dotazem a po dotazu. Pokud to trva dlouho, tak mas dotaz spatne a urcite to jde lepe :) Pripadne nemas spravne nastavene indexy v sql tabulce. Jak jsem psal minule, ten tvuj dotaz te v podstate zajima z opacneho konce. Dodatecne info si muzes pridat LEFT JOINem. Zkus si odpovedet na otazku, co chces mit jako vysledek z dotazu. A tou tabulkou bys mel zacit, kde jsou takove udaje.

'ukaž mi všechny záznamy daného uživatele'
SELECT a.*, b.sloupec AS id2 FROM uzivatele_vazebni a LEFT JOIN uzivatel ... WHERE a.user_id IN (...) ok, ale...

chces vsechno, co najdes k uzivateli
SELECT sloupce FROM uzivatele a LEFT JOIN uzivatel_terminy b ... WHERE b.datum1... and b.datum2

IN je ok, ale SELECT ti vybere nejaka data, ktera pak uz nejsou indexovana. Takze IN ma mnohem pak nepracuje s indexem. Tusim, ze index muzes nastavovat u tmp a cursor pomocnych tabulek.

 
Nahoru Odpovědět 25. dubna 7:24
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 12 zpráv z 12.