[PHP] Hoe geheugen leegmaken van class?

Pagina: 1
Acties:
  • 3.908 views sinds 30-01-2008
  • Reageer

Onderwerpen


Acties:
  • 0 Henk 'm!

  • pierre-oord
  • Registratie: April 2002
  • Laatst online: 10-02 23:00
Beste Tweakers,

In een script waarin ik een groot aantal PDF bestanden probeer te genereren en daarna te e-mailen, loop ik tegen een geheugengebruik probleem aan:

code:
1
Fatal error: Allowed memory size of 16777216 bytes exhausted (tried to allocate 1245184 bytes) in /www/vhosts/gameforaday.com/www/dompdf/lib/class.pdf.php(2219) : eval()'d code on line 5914


Oftewel: 16MB geheugen is er voor het script dat is opgebruikt, en het script wil nog 1MB toekennen, even grof. Het probleem ontstaat doordat er meerdere PDF's worden gegenereerd. Bij de 4e PDF ontstaat dit probleem.

De relevante code is:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
function blaat(){
    $mail = new PHPMailer();
    $mail->Mailer   = 'mail';
    $mail->From     = $set['company-email'];
    $mail->FromName = $set['company-name']. ' administration system';
    $mail->AddAddress($to_email); 
    $mail->AddReplyTo($set['company-email'], $set['company-name']);
    $mail->IsHTML(false);
    $mail->Subject  =  'blabla';
    $mail->Body     =  $result;

    // create and attach the PDF invoice.
    require_once("dompdf/dompdf_config.inc.php");
    $dompdf = new DOMPDF();
    $dompdf->load_html(generate_pdf($_GET['id']));
    error_reporting(E_ERROR); // DomPDF is not very cleanly coded.
    $dompdf->render();
    $filename = 'blabla.pdf';
    $mail->AddStringAttachment($dompdf->output(), $filename);
    error_reporting(E_ALL);

    if(!$mail->Send()) {
        echo 'Message was NOT sent! <br>';
        echo 'Mailer Error: '.$mail->ErrorInfo;
    } else {
        echo 'Message sent <br>';
    }
    unset($mail);
    unset($dompdf);
}


Zoals je ziet heb ik al met "unset" geprobeerd alles uit het geheugen te krijgen. Ook "= NULL" heb ik geprobeerd. Het lijkt echter allemaal niet te werken. Ook met google waren dit de enige gevonden mogelijkheden.
Helaas ben ik nog niet zo sterk in classes, gebruiken oke, maar maken, nee :)
Het zal vast iets heel kleins en makkelijks zijn!

Acties:
  • 0 Henk 'm!

Verwijderd

misschien kan je eens proberen om

$mail = new PHPMailer();
$dompdf = new DOMPDF();

te veranderen in

$mail &= new PHPMailer();
$dompdf &= new DOMPDF();

want volgens mij unset ie nou alleen een copy van het object en niet het werkelijke object.

Acties:
  • 0 Henk 'm!

Verwijderd

oops foutje....dit moet het zijn:

$mail =& new PHPMailer();
$dompdf =& new DOMPDF();

Acties:
  • 0 Henk 'm!

  • pierre-oord
  • Registratie: April 2002
  • Laatst online: 10-02 23:00
d4rkblade: Ik weet niet wat die & doet, maar het lost iig niet het probleem op... Heb je nog andere ideeën?

Acties:
  • 0 Henk 'm!

  • kokx
  • Registratie: Augustus 2006
  • Laatst online: 13-09 20:30

kokx

WIN

@d4rkblade: Dat maakt echt helemaal niets uit. In php5 hoor je er zelfs een E_STRICT error door te krijgen, aangezien het eigenlijk niet eens mag.

Want bij het aanmaken van een object krijg je automatisch een reference.

Acties:
  • 0 Henk 'm!

  • Optix
  • Registratie: Maart 2005
  • Laatst online: 12-08 19:46
PHP:
1
ini_set('memory_limit', '16M')
(of hoger)
Verwijderd schreef op zaterdag 07 juli 2007 @ 15:26:
oops foutje....dit moet het zijn:

$mail =& new PHPMailer();
$dompdf =& new DOMPDF();
& onderdrukt geen fatal errors voor zover ik weet :)

[ Voor 78% gewijzigd door Optix op 07-07-2007 16:01 ]

.


Acties:
  • 0 Henk 'm!

  • robbert
  • Registratie: April 2002
  • Laatst online: 20:37
Optix schreef op zaterdag 07 juli 2007 @ 15:57:
PHP:
1
ini_set('memory_limit', '16M')
(of hoger)
Daarmee stel je alleen maar het probleem uit. TS wil dat het geheugen telkens opgeruimd wordt. Jij vergroot het geheugen, als die dan weer meer pdf bestanden per keer wil genereren krijgt die weer een probleem.
& onderdrukt geen fatal errors voor zover ik weet :)
& wijst de waarde "by reference" toe. Echter slaat dit nergens op bij een constructor zoals kokx al zei.

Acties:
  • 0 Henk 'm!

  • pierre-oord
  • Registratie: April 2002
  • Laatst online: 10-02 23:00
robbert schreef op zaterdag 07 juli 2007 @ 16:09:
[...]

Daarmee stel je alleen maar het probleem uit. TS wil dat het geheugen telkens opgeruimd wordt. Jij vergroot het geheugen, als die dan weer meer pdf bestanden per keer wil genereren krijgt die weer een probleem.

[...]

& wijst de waarde "by reference" toe. Echter slaat dit nergens op bij een constructor zoals kokx al zei.
Precies, het gaat om tientallen PDF's, en dit gebeurd al bij de 4e. 'k hoop toch nog op een oplossing, ik begrijp ook niet waarom dat geheugen open blijft staan.

Acties:
  • 0 Henk 'm!

  • robbert
  • Registratie: April 2002
  • Laatst online: 20:37
pierre-oord schreef op zaterdag 07 juli 2007 @ 16:11:
[...]


Precies, het gaat om tientallen PDF's, en dit gebeurd al bij de 4e. 'k hoop toch nog op een oplossing, ik begrijp ook niet waarom dat geheugen open blijft staan.
Heeft php eigenlijk wel een garbage collector, of ruimt die enkel automatisch zijn geheugen op als het script termineert?

Acties:
  • 0 Henk 'm!

Verwijderd

& teken maakt wel uit bij php4.......maar jij gebruikt dus php5??

maar volgens mij destruct ie die $mail en $dompdf objecten niet goed. Is et mogelijk om te forceren dat de garbage collector dit gelijk opruimt??

Acties:
  • 0 Henk 'm!

  • robbert
  • Registratie: April 2002
  • Laatst online: 20:37
Verwijderd schreef op zaterdag 07 juli 2007 @ 16:16:
& teken maakt wel uit bij php4.......maar jij gebruikt dus php5??
Classen en arrays zijn in PHP5 altijd by reference toe, waar dit in PHP4 niet was.

Maar bij een constructor zou dit toch niet uitmaken, of wel? PHP4 gaat toch niet dat hele object wat je net hebt gecreëerd kopiëren of iets debiels?

[ Voor 9% gewijzigd door robbert op 07-07-2007 16:20 ]


Acties:
  • 0 Henk 'm!

  • Wim Leers
  • Registratie: Januari 2004
  • Laatst online: 09-09 08:00
Alternatief: een webpagina telkens laten updaten als je een nieuwe pdf hebt aangemaakt, en dus 1 pdf per keer dat je je .php aanroept laten maken. Updaten dmv AJAX of iets gelijkaardig.

Acties:
  • 0 Henk 'm!

Verwijderd

robbert schreef op zaterdag 07 juli 2007 @ 16:19:
[...]

Classen en arrays zijn in PHP5 altijd by reference toe, waar dit in PHP4 niet was.

Maar bij een constructor zou dit toch niet uitmaken, of wel? PHP4 gaat toch niet dat hele object wat je net hebt gecreëerd kopiëren of iets debiels?
dus wel... :X

Acties:
  • 0 Henk 'm!

  • robbert
  • Registratie: April 2002
  • Laatst online: 20:37
Bashrat schreef op zaterdag 07 juli 2007 @ 16:19:
Alternatief: een webpagina telkens laten updaten als je een nieuwe pdf hebt aangemaakt, en dus 1 pdf per keer dat je je .php aanroept laten maken. Updaten dmv AJAX of iets gelijkaardig.
Of een php script dat je met exec uitvoert welke je pdf bestand oplevert.

Acties:
  • 0 Henk 'm!

  • robbert
  • Registratie: April 2002
  • Laatst online: 20:37
offtopic:
Heb je toevallig ook een bron waar dat staat?

Acties:
  • 0 Henk 'm!

Verwijderd

lees net dat de garbage collector gelijk zou moeten werken op het moment dat je unset() aanroept....
misschien eens kijken of je iets met mysql_free_result() kan doen??

http://nl2.php.net/mysql_free_result

Acties:
  • 0 Henk 'm!

  • robbert
  • Registratie: April 2002
  • Laatst online: 20:37
Verwijderd schreef op zaterdag 07 juli 2007 @ 16:21:
lees net dat de garbage collector gelijk zou moeten werken op het moment dat je unset() aanroept....
misschien eens kijken of je iets met mysql_free_result() kan doen??

http://nl2.php.net/mysql_free_result
Uhmm...
result

The result resource that is being evaluated. This result comes from a call to mysql_query().
Ook maar even uitgeprobeerd:
PHP:
1
2
$blaat = new StdClass();
mysql_free_result ($blaat);

DIt geeft:
Warning: mysql_free_result(): supplied argument is not a valid MySQL result resource in /home/robbert/public_html/zeik.php on line 3

Acties:
  • 0 Henk 'm!

Verwijderd

robbert schreef op zaterdag 07 juli 2007 @ 16:21:
[...]

offtopic:
Heb je toevallig ook een bron waar dat staat?
sorry je hebt gelijk 8)7 blijkbaar referenced ie wel wanneer je de klasse instantieert

Acties:
  • 0 Henk 'm!

Verwijderd

robbert schreef op zaterdag 07 juli 2007 @ 16:24:
[...]

Uhmm...

[...]


Ook maar even uitgeprobeerd:
PHP:
1
2
$blaat = new StdClass();
mysql_free_result ($blaat);

DIt geeft:

[...]
hmm dat betekend dat php dus een resultaat ziet als een mysql resultaat......dan werkt het idd niet

Acties:
  • 0 Henk 'm!

Verwijderd

je kan misschien wel met memory_get_usage() even bekijken of ie de objecten wel goed opruimt....

Acties:
  • 0 Henk 'm!

  • GlowMouse
  • Registratie: November 2002
  • Niet online
In PHP 5.2.0, 5.2.1 en 5.2.2 zijn enkele verbeteringen doorgevoerd met betrekking tot geheugengebruik en geheugenmeting. Welke versie van PHP gebruik je?

Heb je al geprobeerd direct de vierde PDF te genereren? Wanneer die vierde net wat groter is dan de eerste drie, kan het namelijk zo zijn dat die eerste drie er niets mee te maken hebben.

Uit de melding blijkt ook dat je eval() gebruikt. Heb je ook al eens zonder eval geprobeerd te werken?

d4rkblade: je kunt ipv 3x achter elkaar een reactie te posten beter de edit-knop gebruiken

[ Voor 10% gewijzigd door GlowMouse op 07-07-2007 16:33 ]


Acties:
  • 0 Henk 'm!

Verwijderd

ben nog nieuw hier.....maar waar zit die edit knop??

ik zie em al.......was niet ingelogt

[ Voor 27% gewijzigd door Verwijderd op 07-07-2007 16:38 ]


Acties:
  • 0 Henk 'm!

  • Spider.007
  • Registratie: December 2000
  • Niet online

Spider.007

* Tetragrammaton

De makkelijkste oplossing is zoals gezegd om via exec de cli-versie van PHP aan te roepen; als de PHP Garbage collector het object niet opruimt dan ga jij dat ook niet geforceerd voor elkaar krijgen; en heb je waarschijnlijk te maken met cyclische referenties. Een goede oplossing vereist dan ook om die referenties op te ruimen zodat de GC het opruimen kan doen.

Daarnaast vraag ik me af of je je dompdf object niet gewoon kan hergebruiken binnen de loop? Dus daarbuiten aanmaken en vervolgens erbinnen dezelfde calls behouden. Hetzelfde geld voor je PHPMailer :)

---
Prozium - The great nepenthe. Opiate of our masses. Glue of our great society. Salve and salvation, it has delivered us from pathos, from sorrow, the deepest chasms of melancholy and hate


Acties:
  • 0 Henk 'm!

  • pierre-oord
  • Registratie: April 2002
  • Laatst online: 10-02 23:00
Oke, even wat nieuwe informatie:

Ik draai PHP 5.2.2 (zie ook http://admin.flexbouncer.com/phpinfo.php )
Hij probeert nu 5 PDF's te genereren, van wie ieder dezelfde content bevat (en dus even groot). Uit de foutmelding blijkt ook dat er 16MB beschikbaar is voor het script, en dat nog 1MB allocaten niet wil lukken (die 16MB zit dus vol). Als alles netjes werd geleegd, was geen 16MB in gebruik natuurlijk. Het script bevat wel wat MySQL code, maar dit heeft voor het PDF gebeuren nooit tot problemen geleid, het zijn echt de eerste 3 PDF's die zorgen voor het grote geheugen gebruik.

Ik maak gebruik van de class "dompdf". In principe wil ik niet iets wijzigen aan deze class, tenzij er echt iets goed fout zit dat ik niet ná de run kan herstellen. In die class word schijnbaar "eval" gebruikt, maar ik zelf gebruik die functie niet.

Het script moet ook werken op PHP 4, dus ik zal die & wel laten staan. Ik werk niet in E_STRICT error reporting, maar in E_ALL (ivm PHP4).

Wat betreft workarounds: Op dat idee was ik al gekomen, maar die maken zaken veel gecompliceerder dan dat ze zouden moeten zijn.

Zoals gevraagd heb ik met memory_get_usage wat meer info laten weergeven:
______________________________________________________________________________________________________________
Memory in use: 0.5 MB.
Message sent [Remember-message sent to pierre.oord@gmail.com]
______________________________________________________________________________________________________________
Memory in use: 8.5 MB.
Message sent [Remember-message sent to pierre.oord@gmail.com]
______________________________________________________________________________________________________________
Memory in use: 10.8 MB.
Message sent [Remember-message sent to pierre.oord@gmail.com]
______________________________________________________________________________________________________________
Memory in use: 13 MB.

Fatal error: Allowed memory size of 16777216 bytes exhausted (tried to allocate 1245184 bytes) in /www/vhosts/gameforaday.com/www/dompdf/lib/class.pdf.php(2219) : eval()'d code on line 5914
De eerste keer gaat het geheugen gebruik dus veel harder omhoog dan de 2e keer. Na het weghalen van de "unset"'s blijven de getallen precies gelijk.

Deze functie kwam ik nog tegen: http://www.php.net/destruct maar volgens mij moet dat "in" de class zelf staan.
Ook:
unset($GLOBALS['mail']);
unset($GLOBALS['dompdf']);
Helpt niet (dat vond ik net met google). Ik hoop dat er toch nog iemand een oplossing weet!

p.s. layout hier gaat stuk van veel underscores in quotes?

[ Voor 7% gewijzigd door pierre-oord op 07-07-2007 16:55 ]


Acties:
  • 0 Henk 'm!

Verwijderd

hier een artikel over memory management in php 5.2

http://www.ibm.com/developerworks/opensource/library/os-php-v521/?ca=dgr-lnxw16PHP5.2-Memory

misschien even op meerdere plaatsen memory_get_usage() gebruiken om zo exact te kijken waar het mis gaat.

Op de site van dompdf wordt aangeraden om je memory limit te vergroten naar 32MB......niet dat dit een oplossing is maar misschien toch verstandig om dit in de toekomst aan te passen.

[ Voor 20% gewijzigd door Verwijderd op 07-07-2007 17:09 ]


Acties:
  • 0 Henk 'm!

  • Michiel
  • Registratie: Augustus 2006
  • Laatst online: 30-09-2023
Elke variabele-naam in PHP is maar een verwijzing naar de werkelijke waarde. En een waarde kan meerdere verwijzingen hebben. unset() verwijdert alleen die ene verwijzing. Het geheugen wordt door de garbage collector pas vrij gegeven als alle verwijzingen ernaar weg zijn.

Als ik jou was zou ik dus kijken of je ergens anders nog verwijzingen hebt opgeslagen naar je objecten. Let op: als je de = operator gebruikt bij objecten maak je een verwijzing, niet een kopie.

Oh, en zelfs in PHP 4 is het gebruik van =& bij het maken van een nieuw object onzin.

Acties:
  • 0 Henk 'm!

Verwijderd

In het TS staat dat verschillende PDFs worden gegenereerd, aan een e-mail worden gehangen, welke verstuurd wordt. In de laatste debug lijkt het erop dat per PDF een e-mail wordt verstuurd. Dat is anders, maar dat terzijde. Evenals het feit dat dompdf het bijschrift "The PHP 5 HTML to PDF Converter" heeft =]

In dit geval ben ik benieuwd naar het geheugengebruik op de volgende punten in het script: [a1] voor de instantie van $mail, [b1] voor de instantie van $dompdf, [c1] voor $dompdf->output() en [c2] na $dompdf->output(), [b2] na unset($dompdf) en [a2] na unset($mail). Misschien dat dit meer inzicht oplevert in het knelpunt.

Acties:
  • 0 Henk 'm!

  • pierre-oord
  • Registratie: April 2002
  • Laatst online: 10-02 23:00
onezero, zoals gevraagd hier de info:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
______________________________________________________________________________________________________________
Memory in use: 0.6 MB.
User pierre.oord@gmail.com should pay within 10 days for invoice 1, sending notification...
Mem-usage Start: 0.6 MB
Mem-usage before new PHPMailer(): 0.6 MB
Mem-usage before generation part: 0.6 MB
Mem-usage before new DOMPDF(): 0.8 MB
Mem-usage before load_html: 1 MB
Mem-usage before render: 1.1 MB
Mem-usage before attaching: 8.5 MB
Mem-usage before sending: 8.5 MB
Message sent [Remember-message sent to pierre.oord@gmail.com]
Mem-usage before unsetting: 8.5 MB
Mem-usage end: 8.5 MB
______________________________________________________________________________________________________________
Memory in use: 8.5 MB.
User pierre.oord@gmail.com should pay within 10 days for invoice 2, sending notification...
Mem-usage Start: 8.5 MB
Mem-usage before new PHPMailer(): 8.5 MB
Mem-usage before generation part: 8.5 MB
Mem-usage before new DOMPDF(): 8.5 MB
Mem-usage before load_html: 8.5 MB
Mem-usage before render: 8.6 MB
Mem-usage before attaching: 10.8 MB
Mem-usage before sending: 10.8 MB
Message sent [Remember-message sent to pierre.oord@gmail.com]
Mem-usage before unsetting: 10.8 MB
Mem-usage end: 10.8 MB
______________________________________________________________________________________________________________
Memory in use: 10.8 MB.
User pierre.oord@gmail.com should pay within 10 days for invoice 3, sending notification...
Mem-usage Start: 10.8 MB
Mem-usage before new PHPMailer(): 10.8 MB
Mem-usage before generation part: 10.8 MB
Mem-usage before new DOMPDF(): 10.8 MB
Mem-usage before load_html: 10.8 MB
Mem-usage before render: 10.8 MB
Mem-usage before attaching: 13 MB
Mem-usage before sending: 13 MB
Message sent [Remember-message sent to pierre.oord@gmail.com]
Mem-usage before unsetting: 13 MB
Mem-usage end: 13 MB
______________________________________________________________________________________________________________
Memory in use: 13 MB.
User pierre.oord@gmail.com should pay within 10 days for invoice 4, sending notification...
Mem-usage Start: 13 MB
Mem-usage before new PHPMailer(): 13 MB
Mem-usage before generation part: 13 MB
Mem-usage before new DOMPDF(): 13 MB
Mem-usage before load_html: 13 MB
Mem-usage before render: 13.1 MB


PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
function attendeer_gebruiker($id, $date_pay_before, $firstname, $lastname, $invoicenumber, $to_email) {
    global $set;
    echo 'Mem-usage Start: '.round(memory_get_usage() / 1000 / 1000, 1).' MB<br>' ;
    $result = $set['user_mail_remember'];
    $result = str_replace("<date_today>", gmdate("d-m-Y"), $result);
    $result = str_replace("<date_pay_before>", gmdate("d-m-Y", $date_pay_before), $result);
    $result = str_replace("<firstname>", $firstname, $result);
    $result = str_replace("<lastname>", $lastname, $result);
    $result = str_replace("<invoicenumber>", $invoicenumber, $result);
    $result = str_replace("<company-name>", $set['company-name'], $result);
    
    echo 'Mem-usage before new PHPMailer(): '.round(memory_get_usage() / 1000 / 1000, 1).' MB<br>' ;
    $mail = new PHPMailer();
    $mail->Mailer   = 'mail';
    $mail->From     = $set['company-email'];
    $mail->FromName = $set['company-name']. ' administration system';
    $mail->AddAddress($to_email); 
    $mail->AddReplyTo($set['company-email'], $set['company-name']);
    $mail->IsHTML(false);
    $mail->Subject  =  'Payment invoice '.$invoicenumber;
    $mail->Body     =  $result;

    echo 'Mem-usage before generation part: '.round(memory_get_usage() / 1000 / 1000, 1).' MB<br>' ;
    // create and attach the PDF invoice.
    $_GET['method'] = 'none';
    $executed_by_script = true;
    $_GET['invoiceid'] = $invoicenumber;
    require_once('generate_invoice.php');
    require_once("dompdf/dompdf_config.inc.php");
    echo 'Mem-usage before new DOMPDF(): '.round(memory_get_usage() / 1000 / 1000, 1).' MB<br>' ;
    $dompdf = new DOMPDF();
    echo 'Mem-usage before load_html: '.round(memory_get_usage() / 1000 / 1000, 1).' MB<br>' ;
    $dompdf->load_html(generate_invoice($_GET['invoiceid']));
    error_reporting(E_ERROR); // DomPDF is not very cleanly coded.
    echo 'Mem-usage before render: '.round(memory_get_usage() / 1000 / 1000, 1).' MB<br>' ;
    $dompdf->render();
    $filename = 'invoice'.$_GET['invoiceid'].'.pdf';
    echo 'Mem-usage before attaching: '.round(memory_get_usage() / 1000 / 1000, 1).' MB<br>' ;
    $mail->AddStringAttachment($dompdf->output(), $filename);
    //error_reporting(E_ALL);
    error_reporting(E_STRICT);
    echo 'Mem-usage before sending: '.round(memory_get_usage() / 1000 / 1000, 1).' MB<br>' ;

    if(!$mail->Send()) {
        echo 'Message was NOT sent! <br>';
        echo 'Mailer Error: '.$mail->ErrorInfo;
    } else {
        echo 'Message sent [Remember-message sent to '.$to_email.']<br>';
    }
    
    echo 'Mem-usage before unsetting: '.round(memory_get_usage() / 1000 / 1000, 1).' MB<br>' ;
    unset($GLOBALS['mail']);
    unset($GLOBALS['dompdf']);
    echo 'Mem-usage end: '.round(memory_get_usage() / 1000 / 1000, 1).' MB<br>' ;
}


Even ook de volledige code. Deze functie word aangeroepen na een query. Tussen de functie aanroepen veranderd het geheugengebruik niet, dus daar zal het probleem niet liggen. Aangezien het een functie betreft, word als het goed is alle verwijzingen weggehaald die ik zelf heb gemaakt, toch?

edit:
Dit geeft ook mij wat meer duidelijkheid: Bijvoorbeeld voor het invoegen van HTML is alleen de 1e keer geheugen nodig, de 2e keer niet meer. Dat komt natuurlijk omdat ik dan de oude waarden overschrijf, en aangezien de PDF's dezelfde info bevatten (bijna) is die waarde gelijk. Waarom kan ik alles wat die class doet niet trashen? Misschien moet ik die class eens goed bekijken, zou die allerlei globale dingen maken?

[ Voor 3% gewijzigd door pierre-oord op 07-07-2007 18:00 ]


Acties:
  • 0 Henk 'm!

  • Rense Klinkenberg
  • Registratie: November 2000
  • Laatst online: 03-09 14:12
Wellicht dat de functies debug_zval_dump en debug_backtrace handig kunnen zijn voor het achterhalen van de verschillende refenties naar de objecten.

Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 21-09 02:21

Janoz

Moderator Devschuur®

!litemod

Ik vermoed dat je hier gewoon keihard tegen de beperkingen van php aan aan het lopen bent. Php is bedoeld voor de korte kleine requestjes. Memory managment was nooit een issue geweest omdat een een scriptje enkel 1 request leeft. ZOdra alles verzonden was kon gewoon de complete bulk aan geheugen vrijgegeven worden (of zelfs het hele proces opgeruimt worden). Meer dan dat heeft memory managment in php niet voorgesteld en meer was ook helemaal niet nodig.

Om het geheugen op te ruimen zul je dus gewoon losse processjes moeten maken middels het executen van een script voor elke mailing. Een andere oplossing is er in php blijkbaar gewoon niet. Wil je het toch in 1 script/actie doen dan zul je naar de iets serieuzere platformen moeten kijken.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • storeman
  • Registratie: April 2004
  • Laatst online: 23:07
unset($GLOBALS['mail']);
unset($GLOBALS['dompdf']);
Dit schoot mij ook door het hoofd, alleen moet je niet de class gebruiken, maar de objectnaam.

PHP:
1
2
3
$obj = new StdObj();

unset($GLOBALS[$obj]);


Dat zou het geheugen vrij moeten maken. Een andere manier is om de variabelen in plaats van een global scope te geven een beperkte scope, dus de hele mikmak in een functie gooien. Of de naam van het object steeds opnieuw gebruiken, zoals eerder aangedragen.

Overigens ondersteunt pdfdom geen php4! Ik was ook al geinteresseerd in die class, maar is php 5 only, helaas. Ik ben zelf aan de slag gegaan met ezPdf, dit ondersteunt echter geen html2pdf.

"Chaos kan niet uit de hand lopen"


Acties:
  • 0 Henk 'm!

  • kokx
  • Registratie: Augustus 2006
  • Laatst online: 13-09 20:30

kokx

WIN

storeman schreef op zaterdag 07 juli 2007 @ 21:48:
[...]


Dit schoot mij ook door het hoofd, alleen moet je niet de class gebruiken, maar de objectnaam.

PHP:
1
2
3
$obj = new StdObj();

unset($GLOBALS[$obj]);


Dat zou het geheugen vrij moeten maken. Een andere manier is om de variabelen in plaats van een global scope te geven een beperkte scope, dus de hele mikmak in een functie gooien. Of de naam van het object steeds opnieuw gebruiken, zoals eerder aangedragen.
Helaas dat kan niet in php, doe het eens zo:
PHP:
1
2
3
$obj = new StdClass();

unset($GLOBALS['obj']);


Het is btw ook StdClass (de standaard class dan). Geen StdObj, want het is en blijft een class.

Acties:
  • 0 Henk 'm!

  • pierre-oord
  • Registratie: April 2002
  • Laatst online: 10-02 23:00
kokx: Dat heb al geprobeerd, zie m'n code.

Verder: er moet toch wel een manier zijn? Ik ga nu even die IBM info doornemen, en nog wat meer googlen... ik kan ook maar geen mensen vinden met mijn probleem.

Acties:
  • 0 Henk 'm!

  • storeman
  • Registratie: April 2004
  • Laatst online: 23:07
@kokx: je hebt helemaal gelijk!

@pierre-oord: Ik heb net ff een testfile gemaakt:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$obj = new stdClass();

var_dump($obj);
var_dump($GLOBALS['obj']);

unset($GLOBALS['obj']);

var_dump($obj);
var_dump($GLOBALS['obj']);

// Output:
/**
object(stdClass)(0) { } object(stdClass)(0) { }
Notice: Undefined variable: obj in d:\www\_research\objectcleaning.php on line 10
NULL
Notice: Undefined index: obj in d:\www\_research\objectcleaning.php on line 11
NULL
*/


Het lijkt me dus wel dat het geheugen vrijgemaakt wordt. Overigens blijkt net dat dit ook geldt wanneer je alleen unset('obj'); uitvoerd, dan wordt de globale ook naar NULL gezet.

Jij zegt dat dat het probleem niet oplost. Wanneer je de variabele hergebruikt dan?

PHP:
1
2
3
4
5
6
7
8
9
//pdf1
$pdf = new DomPDF();

// pdf1 uitpoepen

// pdf2
$pdf = new DomPDF();

// etc...


In principe zou php dan steeds naar dezelfde geheugen locatie moeten schrijven.
Voor elke pdf een functie bouwen helpt ook niet? De scope van een variabele is dan beperkt.

"Chaos kan niet uit de hand lopen"


Acties:
  • 0 Henk 'm!

  • dingstje
  • Registratie: Augustus 2002
  • Laatst online: 02-01-2024
Je variablen $dompdf en $mailer zijn function scope, terwijl je de variablen dompdf en mailer in de global scope probeert te unsetten.

code:
1
2
    unset($GLOBALS['mail']);
    unset($GLOBALS['dompdf']);


veranderen in:

code:
1
2
    unset($mail);
    unset($dompdf);

If you can't beat them, try harder


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 21-09 02:21

Janoz

Moderator Devschuur®

!litemod

dingstje schreef op zaterdag 07 juli 2007 @ 23:38:
Je variablen $dompdf en $mailer zijn function scope, terwijl je de variablen dompdf en mailer in de global scope probeert te unsetten.

code:
1
2
    unset($GLOBALS['mail']);
    unset($GLOBALS['dompdf']);


veranderen in:

code:
1
2
    unset($mail);
    unset($dompdf);
Als dat zou werken zou ik het heel vreemd vinden. Sowieso zou je verwachten dat alles opgeruimt zou worden zodra je de function scope verlaat.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • dingstje
  • Registratie: Augustus 2002
  • Laatst online: 02-01-2024
Janoz schreef op zaterdag 07 juli 2007 @ 23:40:
[...]

Als dat zou werken zou ik het heel vreemd vinden. Sowieso zou je verwachten dat alles opgeruimt zou worden zodra je de function scope verlaat.
Ik heb het lokaal getest:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
define('GROOT_BESTAND', '...');

function testUnsetGlobal() {
        echo "Testing with unset \$GLOBALS['file']\n";
        echo 'Memory usage at start: ' . memory_get_usage() . "\n";;
        $file = file_get_contents(GROOT_BESTAND);
        echo 'Memory usage after loading file: ' . memory_get_usage() . "\n";
        unset($GLOBALS['file']);
        echo 'Memory usage after unsetting $GLOBALS[\'file\']: ' . memory_get_usage() . "\n\n";
}

function testUnsetLocal() {
        echo "Testing with unset \$file\n";
        echo 'Memory usage at start: ' . memory_get_usage() . "\n";;
        $file = file_get_contents(GROOT_BESTAND);
        echo 'Memory usage after loading file: ' . memory_get_usage() . "\n";
        unset($file);
        echo 'Memory usage after unsetting $file: ' . memory_get_usage() . "\n\n";
}

testUnsetGlobal();
testUnsetLocal();
?>


code:
1
2
3
4
5
6
7
8
9
Testing with unset $GLOBALS['file']
Memory usage at start: 55840
Memory usage after loading file: 5057360
Memory usage after unsetting $GLOBALS['file']: 5057416

Testing with unset $file
Memory usage at start: 56200
Memory usage after loading file: 5057432
Memory usage after unsetting $file: 56200


PHP zou inderdaad veel geheugen kunnen besparen door telkens de variablen te unsetten na een function call, de vraag is of dat de performance ten goede komt (binnen een one-request context). Een object destructen kost ook tijd...

If you can't beat them, try harder


Acties:
  • 0 Henk 'm!

  • pierre-oord
  • Registratie: April 2002
  • Laatst online: 10-02 23:00
storeman: in de functie doe ik al de var hergebruiken.
dingstje: beide methodes van unset werken niet
janoz: precies wat je zegt: ik gebruik een functie, dus alles wat daarin staat, zou ik eigenlijk niet hoeven te legen omdat een functie dat zou moeten doen nadat die is afgelopen.

Schijnbaar stopt dompdf iets in het geheugen, waar alleen maar steeds iets word bijgezet, en wat niet word overschreven bij de 2e run van dompdf? Ik begrijp er echt niets van.

edit:

Ik heb ook $dompdf->__destruct(); nog geprobeerd, maar dan sterft het script direct. Ja, opgeruimd, dat is het dan wel :P

[ Voor 12% gewijzigd door pierre-oord op 08-07-2007 00:13 ]


Acties:
  • 0 Henk 'm!

  • dingstje
  • Registratie: Augustus 2002
  • Laatst online: 02-01-2024
edit:
hier stond onzin


Eventjes lokaal mijn testje aangepast en meerdere malen die functie aangeroepen zonder unset() erin, en het geheugen wordt hier toch vrijgemaakt na elke functie-aanroep. Zal dus inderdaad wel aan die DOMPDF moeten liggen.

(maar hoe dan ook heeft unset($GLOBALS['dompdf']); geen zin in je function scope :p)

[ Voor 102% gewijzigd door dingstje op 08-07-2007 00:28 ]

If you can't beat them, try harder


Acties:
  • 0 Henk 'm!

  • pierre-oord
  • Registratie: April 2002
  • Laatst online: 10-02 23:00
dingstje, dat vind ik vreemd. Wat is jou output dan?

Ik heb even een script gemaakt zonder de rommel in het andere script, zodat iedereen met dezelfde code kan testen als je dat wil.
Code vind je hier: http://pierre.flexbouncer.com/testfile.txt
Alleen even los DOMPDF downloaden.

Ik heb ook de maker een mailtje gestuurd inmiddels, eens afwachten of hij nog een reactie geeft.

Acties:
  • 0 Henk 'm!

  • dingstje
  • Registratie: Augustus 2002
  • Laatst online: 02-01-2024
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
function test() {
        echo "Starting new testrun\n";
        echo 'Memory usage at start: ' . memory_get_usage() . "\n";
        $obj = new StdClass;
        $obj->file = file_get_contents(GROOT_BESTAND);
        echo 'Memory usage at end (in function): ' . memory_get_usage() . "\n";

test();
echo 'Memory usage at end (out of function): ' . memory_get_usage() . "\n\n";
test();
echo 'Memory usage at end (out of function): ' . memory_get_usage() . "\n\n";
test();
echo 'Memory usage at end (out of function): ' . memory_get_usage() . "\n\n";


Output:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Starting new testrun
Memory usage at start: 57768
Memory usage at end (in function): 5059480
Memory usage at end (out of function): 57984

Starting new testrun
Memory usage at start: 58304
Memory usage at end (in function): 5059536
Memory usage at end (out of function): 57984

Starting new testrun
Memory usage at start: 58304
Memory usage at end (in function): 5059536
Memory usage at end (out of function): 57984


Zoals je ziet is op het einde van de functie bijna 5 MB geheugen in gebruik, en wanneer we uit de functie gedropt zijn terug slechts 57 KB. PHP ruimt $obj dus zelf netjes op bij het verlaten van de functie. PHP 5.2.3 overigens.

If you can't beat them, try harder


Acties:
  • 0 Henk 'm!

  • pierre-oord
  • Registratie: April 2002
  • Laatst online: 10-02 23:00
dingstje schreef op zondag 08 juli 2007 @ 00:58:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
function test() {
        echo "Starting new testrun\n";
        echo 'Memory usage at start: ' . memory_get_usage() . "\n";
        $obj = new StdClass;
        $obj->file = file_get_contents(GROOT_BESTAND);
        echo 'Memory usage at end (in function): ' . memory_get_usage() . "\n";

test();
echo 'Memory usage at end (out of function): ' . memory_get_usage() . "\n\n";
test();
echo 'Memory usage at end (out of function): ' . memory_get_usage() . "\n\n";
test();
echo 'Memory usage at end (out of function): ' . memory_get_usage() . "\n\n";


Output:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Starting new testrun
Memory usage at start: 57768
Memory usage at end (in function): 5059480
Memory usage at end (out of function): 57984

Starting new testrun
Memory usage at start: 58304
Memory usage at end (in function): 5059536
Memory usage at end (out of function): 57984

Starting new testrun
Memory usage at start: 58304
Memory usage at end (in function): 5059536
Memory usage at end (out of function): 57984


Zoals je ziet is op het einde van de functie bijna 5 MB geheugen in gebruik, en wanneer we uit de functie gedropt zijn terug slechts 57 KB. PHP ruimt $obj dus zelf netjes op bij het verlaten van de functie. PHP 5.2.3 overigens.
Het probleem moet dus echt aan dompdf liggen. Ik heb de code daarvan bekeken, en ik zoek eigenlijk naar dingen met "global" woorden.. maar ik kan er niets over vinden. Hoe kan het gebeuren dat na DOMPDF zoveel geheugen in gebruik blijft? Schijnbaar staat er iets globaal gedefineerd, maar wat?

Acties:
  • 0 Henk 'm!

  • GlowMouse
  • Registratie: November 2002
  • Niet online
Wanneer iets globaal gedefinieerd zou zijn, zou je het via print_r($GLOBAL) terug moeten kunnen vinden. Ik zie er echter niets vreemds tussenstaan.

Dat bij $dompdf->__destruct() het hele script stopt, komt omdat __destruct() niet bestaat. Maar omdat je geen errors laat weergeven, merk je dat niet.

[ Voor 34% gewijzigd door GlowMouse op 08-07-2007 01:08 ]


Acties:
  • 0 Henk 'm!

  • robbert
  • Registratie: April 2002
  • Laatst online: 20:37
GlowMouse schreef op zondag 08 juli 2007 @ 01:05:
Wanneer iets globaal gedefinieerd zou zijn, zou je het via print_r($GLOBAL) terug moeten kunnen vinden. Ik zie er echter niets vreemds tussenstaan.

Dat bij $dompdf->__destruct() het hele script stopt, komt omdat __destruct() niet bestaat. Maar omdat je geen errors laat weergeven, merk je dat niet.
Ik vermoed dat ze in dompdf (grote) dingen in static variabelen opslaan, die worden tenslotte niet verwijderd als je het object verwijderd.

@hieronder
Ik hoopte een of andere buffer te ontdekken..
Dikke kans dat ze een static variabele als buffer gebruiken.. Die static variabelen komen ook niet voor in GLOBALS.

[ Voor 15% gewijzigd door robbert op 08-07-2007 01:20 ]


Acties:
  • 0 Henk 'm!

  • pierre-oord
  • Registratie: April 2002
  • Laatst online: 10-02 23:00
GlowMouse schreef op zondag 08 juli 2007 @ 01:05:
Wanneer iets globaal gedefinieerd zou zijn, zou je het via print_r($GLOBAL) terug moeten kunnen vinden. Ik zie er echter niets vreemds tussenstaan.

Dat bij $dompdf->__destruct() het hele script stopt, komt omdat __destruct() niet bestaat. Maar omdat je geen errors laat weergeven, merk je dat niet.
Oja, dat was ik even vergeten van de error_reporting.

Ik kwam ook nog op het idee: var_dump($GLOBALS) -> maar dan krijg je toch een hoop over je scherm...

Ik heb net nog dit gedaan:
PHP:
1
2
3
foreach ($GLOBALS as $key => $value){
    echo $key.'<br>';
}


Maar dat geeft enkel:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
_POST
HTTP_POST_VARS
_GET
HTTP_GET_VARS
_COOKIE
HTTP_COOKIE_VARS
_SERVER
HTTP_SERVER_VARS
_ENV
HTTP_ENV_VARS
_FILES
HTTP_POST_FILES
_REQUEST
html
_dompdf_warnings
_dompdf_show_warnings
_dompdf_debug
value
key


Ik hoopte een of andere buffer te ontdekken.. no luck. Misschien moet ik in de dompdf code gaan spitten, maar er moet toch een andere manier zijn om geheugen vrij te geven? Duidelijk is dat ik wel iets overschrijf, want de eerste run word er veel meer geheugen opgebruikt dan bij de volgende runs (dan overschrijf ik het denk ik). Wat overschrijf ik, vraag ik me dan af. En zouden die 2MB gewoon verlies zijn, net zoals die paar KB als je een 5MB bestand weggooit?

Acties:
  • 0 Henk 'm!

  • StM
  • Registratie: Februari 2005
  • Laatst online: 21-09 16:07

StM

Is in dit geval

_dompdf_warnings
_dompdf_show_warnings
_dompdf_debug

niet wat je zoekt? Misschien die eens unsetten aan het eind...

Acties:
  • 0 Henk 'm!

  • Morax
  • Registratie: Mei 2002
  • Laatst online: 20:32
Site.to.Make schreef op zondag 08 juli 2007 @ 01:21:
Is in dit geval

_dompdf_warnings
_dompdf_show_warnings
_dompdf_debug

niet wat je zoekt? Misschien die eens unsetten aan het eind...
Dat liijken me meer variabelen die gewoon als een setting gebruikt worden als ik naar de namen kijk :)

What do you mean I have no life? I am a gamer, I got millions!


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
pierre-oord schreef op zondag 08 juli 2007 @ 01:17:
En zouden die 2MB gewoon verlies zijn, net zoals die paar KB als je een 5MB bestand weggooit?
offtopic:
Huh? Kun je dat ook uitleggen?

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • StM
  • Registratie: Februari 2005
  • Laatst online: 21-09 16:07

StM

Morax schreef op zondag 08 juli 2007 @ 01:23:
[...]


Dat liijken me meer variabelen die gewoon als een setting gebruikt worden als ik naar de namen kijk :)
Dat zou inderdaad kunnen. Of debug word gebruikt om een heleboel troep op te slaan...

//edit: Helaas, ik heb even de bron bekeken en zo te zien, is het enkel om een paar booleans in op te slaan :'(

[ Voor 15% gewijzigd door StM op 08-07-2007 01:37 ]


Acties:
  • 0 Henk 'm!

  • serkoon
  • Registratie: April 2000
  • Niet online

serkoon

mekker.

Heb je ook al es getest zonder de regel:
code:
1
$mail->AddStringAttachment($dompdf->output(), $filename);

?

Wie weet ligt het helemaal niet aan de PDF-class?

Acties:
  • 0 Henk 'm!

  • pierre-oord
  • Registratie: April 2002
  • Laatst online: 10-02 23:00
RobIII schreef op zondag 08 juli 2007 @ 01:23:
[...]

offtopic:
Huh? Kun je dat ook uitleggen?
dingstje schreef op zondag 08 juli 2007 @ 00:58:
Zoals je ziet is op het einde van de functie bijna 5 MB geheugen in gebruik, en wanneer we uit de functie gedropt zijn terug slechts 57 KB. PHP ruimt $obj dus zelf netjes op bij het verlaten van de functie. PHP 5.2.3 overigens.
Ik verwees naar die test, waarbij ook een klein beetje geheugen niet word teruggegeven.


En serkoon, ja, als je kijkt zul je zien da tik een link heb gegeven naar een los test script.

En die variabelen, ja die heb ik even ge-unset, maar dat mocht niets helpen, het zijn idd alleen config instellingen.

Acties:
  • 0 Henk 'm!

  • serkoon
  • Registratie: April 2000
  • Niet online

serkoon

mekker.

Je test-script bevat weer:
code:
1
$output = $dompdf->output();

Wat wellicht niet goed opgeruimd wordt of ervoor zorgt dat dompdf niet opgeruimd wordt?

Acties:
  • 0 Henk 'm!

  • GlowMouse
  • Registratie: November 2002
  • Niet online
In dompdf/includes/dompdf.cls.php heb ik een destructor toegevoegd:
PHP:
1
2
3
  function __destruct() {
    echo 'Cleaning up!';
  }

En met een heel simpel scriptje:
PHP:
1
2
3
4
5
6
7
require_once("dompdf/dompdf_config.inc.php");
$dompdf = new DOMPDF();
$dompdf->load_html('asdf');
//$dompdf->render();
unset($dompdf);
echo 'asdf';
die();

Met bovenstaand scriptje zie je 'Cleaning up!asdf', wat betekent dat het geheugen direct bij unset wordt vrijgemaakt. Wanneer ik regel 4 uncomment, verandert de output in 'asdfCleaning up!'. Er zal dus nog ergens een verwijzing staan die PHP verhindert het geheugen vrij te maken, die aangemaakt wordt via de renderfunctie. Met unset($GLOBALS) toegevoegd blijft het probleem bestaan.
Met wat verder debuggen, blijkt het probleem te ontstaan bij deze regel (in Class DOMPDF):
PHP:
1
        $root = Frame_Factory::decorate_root( $this->_tree->get_root(), $this );


robbert had dus gelijk:
Ik vermoed dat ze in dompdf (grote) dingen in static variabelen opslaan, die worden tenslotte niet verwijderd als je het object verwijderd.

[ Voor 9% gewijzigd door GlowMouse op 08-07-2007 02:19 ]


Acties:
  • 0 Henk 'm!

  • pierre-oord
  • Registratie: April 2002
  • Laatst online: 10-02 23:00
Glowmouse, hoe kan ik dan die variabelen leeg maken? Dompdf vergeet schijnbaar zelf om $root op te ruimen, maar in de globals zie ik geen $root staan. Waar is $root heen gegaan? Hij is er of is er niet, toch? Ik moet zeggen dat mijn kennis op gebied van classes zeer klein is.

edit:
Spockz in "[PHP] Variabelen doorgeven" in dat topic word nog gesproken over "private" vars. Betekend dat dat die wel worden opgeruimd in een class? mischien moet ik dompdf herschrijven naar private vars?

Dat kost echter een hoop tijd, het liefst trash ik gewoon alles dat overblijft nadat dompdf is gedraaid.

[ Voor 38% gewijzigd door pierre-oord op 08-07-2007 02:28 ]


Acties:
  • 0 Henk 'm!

  • T-MOB
  • Registratie: Maart 2001
  • Laatst online: 22:34
pierre-oord schreef op zondag 08 juli 2007 @ 02:24:
Glowmouse, hoe kan ik dan die variabelen leeg maken? Dompdf vergeet schijnbaar zelf om $root op te ruimen, maar in de globals zie ik geen $root staan. Waar is $root heen gegaan? Hij is er of is er niet, toch? Ik moet zeggen dat mijn kennis op gebied van classes zeer klein is.
Public, protected en private vars hebben te maken met de zgn. visibility. Een public var mag vanaf overal benaderd worden, een protected var alleen vanuit de klasse waarin ie staat en afgeleiden ervan en een private var mag alleen wordne benaderd vanuit de class waarin ie is gedefinieerd.
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class Foo {
  public $foo = 'public';
  protected $bar = 'protected';
  private $quux = 'private';
 
  function getBar() {
    return $this->bar;
  }
  
  function getQuux() {
    return $this->quux;
  }
}

class Bar extends Foo {
  function getBar() {
    return $this->bar;
  }
  
  function getQuux() {
    return $this->quux;
  }
}

$foo = new Foo();
echo $foo->foo; // :public
echo $foo->bar; // !error
echo $foo->getBar(); // :protected
echo $foo->quux; // !error
echo $foo->getQuux(); // :private

$bar = new Bar();
echo $bar->foo; // :public
echo $bar->bar // !error
echo $bar->getBar() // :protected
echo $bar->quux; // !error
echo $bar->getQuux(); // !error


Je probleem heeft hier verder weinig mee te maken... Waar je een probleem mee hebt zijn "static" variabelen. Een static var blijft zijn waarde houden (en dus geheugen gebruiken). In code is het makkelijker uit te leggen:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class StaticExample {
  private static $counter = 0;

  public function __construct() {
    self::$counter++;
  }
  
  public function getNumInstances() {
    return self::$counter;
  }

  public function resetCounter() {
    self::$counter = 0;
  }
}

$obj = new StaticExample();
echo $obj->getNumInstances(); // :1

$obj2 = new StaticExample();
echo $obj2->getNumInstances(); // :2

unset($obj, $obj2);
$obj3 = new StaticExample();
echo $obj3->getNumInstances(); // :3

$obj3->resetCounter();
echo $obj3->getNumInstances(); // :0


Wat er blijkbaar gebeurd in DOMpdf is dat je data in een statisch var gedumpt wordt (zie de functie-call die GlowMouse geeft). Wat je dan wilt doen is de mogelijkheid inbouwen om die static var te legen.

Regeren is vooruitschuiven


Acties:
  • 0 Henk 'm!

  • Michiel
  • Registratie: Augustus 2006
  • Laatst online: 30-09-2023
$root lijkt niet op een statische variabele, want er staat geen self:: voor.

Acties:
  • 0 Henk 'm!

  • T-MOB
  • Registratie: Maart 2001
  • Laatst online: 22:34
Michiel schreef op zondag 08 juli 2007 @ 12:31:
$root lijkt niet op een statische variabele, want er staat geen self:: voor.
Root lijkt idd niet op een statisch var, maar om $root te vullen wordt een statische methode aangeroepen. Wat er in die methode gebeurt weet ik niet, maar dat het geheugen volloopt wijst er op dat er daar ergens een static var wordt gevuld...
PHP:
1
$root = Frame_Factory::decorate_root( $this->_tree->get_root(), $this );


Verder is hoeft er geen "self::" voor een statisch vaiabele te staan, elke class name kan voldoen.

Regeren is vooruitschuiven


Acties:
  • 0 Henk 'm!

  • pierre-oord
  • Registratie: April 2002
  • Laatst online: 10-02 23:00
T-MOB,

Oke, ik begrijp nu wat er open blijft staan. Mij is alleen nog een raadsel: een class zie ik als een soort bundeling van een aantal functies. Waarom kan niet met een simpel commando gewoon alles wat in die class bestaat, worden geleegd? Want nadat ik unset heb gedaan over "$obj2 = new StaticExample", is die class in principe onbereikbaar geworden voor mij. Hoe kan ik het geheugen dan nog legen? dat zou dus moeten gebeuren voordat ik hem unset. Maar waarom gooit PHP zelf dan niet al het geheugen weg, als je er toch niet meer bij kunt? Ik wil gewoon die hele class in het geheugen trashen, en later roep ik (of include ik hem) dan wel weer opnieuw :)

__destruct was ook niet de oplossing. Ik ga nog maar eens goed op de php site wat dingen doornemen, maar ik ben bang dat het uiteindelijk toch werken met temp. files en exec() calls word... en dan weet ik zeker dat veel mensen problemen krijgen met m'n script, doordat ze safemode draaien, de directory niet schrijfbaar is of exec() calls niet toegestaan zijn. Zonder temp file kan ook, maar dat kost weer veel meer code-werk.

Acties:
  • 0 Henk 'm!

  • robbert
  • Registratie: April 2002
  • Laatst online: 20:37
pierre-oord schreef op zondag 08 juli 2007 @ 14:07:
T-MOB,

Oke, ik begrijp nu wat er open blijft staan. Mij is alleen nog een raadsel: een class zie ik als een soort bundeling van een aantal functies. Waarom kan niet met een simpel commando gewoon alles wat in die class bestaat, worden geleegd? Want nadat ik unset heb gedaan over "$obj2 = new StaticExample", is die class in principe onbereikbaar geworden voor mij. Hoe kan ik het geheugen dan nog legen? dat zou dus moeten gebeuren voordat ik hem unset. Maar waarom gooit PHP zelf dan niet al het geheugen weg, als je er toch niet meer bij kunt? Ik wil gewoon die hele class in het geheugen trashen, en later roep ik (of include ik hem) dan wel weer opnieuw :)

__destruct was ook niet de oplossing. Ik ga nog maar eens goed op de php site wat dingen doornemen, maar ik ben bang dat het uiteindelijk toch werken met temp. files en exec() calls word... en dan weet ik zeker dat veel mensen problemen krijgen met m'n script, doordat ze safemode draaien, de directory niet schrijfbaar is of exec() calls niet toegestaan zijn. Zonder temp file kan ook, maar dat kost weer veel meer code-werk.
Een static variabele hoort niet bij een instantie van klasse. Het gene wat je unset is namelijk een instantie van die klasse.

Acties:
  • 0 Henk 'm!

  • T-MOB
  • Registratie: Maart 2001
  • Laatst online: 22:34
pierre-oord schreef op zondag 08 juli 2007 @ 14:07:

Oke, ik begrijp nu wat er open blijft staan. Mij is alleen nog een raadsel: een class zie ik als een soort bundeling van een aantal functies. Waarom kan niet met een simpel commando gewoon alles wat in die class bestaat, worden geleegd? Want nadat ik unset heb gedaan over "$obj2 = new StaticExample", is die class in principe onbereikbaar geworden voor mij. Hoe kan ik het geheugen dan nog legen?
Een static is soort globale variabele die bij een klasse hoort. Je kunt ze (afhankelijk van de visibility) benaderen zonder een instantie van de klasse te hebben. Als het een public static member van een klasse is dan kun je hem direct benaderen. Als het een private static is kan ie alleen worden benaderd vanuit de klasse zelf:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class StaticExample {
  public static $foo = 'I am public static';
  private static $bar = 'I am private static';
  
  public static function getBar() {
    return self::$bar;
  }

  public static function setBar($val) {
    self::$bar = $val;
  }
}

echo StaticExample::$foo; // :I am public static
StaticExample::$foo = 'changed';
echo StaticExample::$foo; // :changed

echo StaticExample::$bar // !error
echo StaticExample::getBar(); // :I am private static
StaticExample::setBar('changed');
echo StaticExample::getBar(); // :changed

Regeren is vooruitschuiven


Acties:
  • 0 Henk 'm!

  • Gwaihir
  • Registratie: December 2002
  • Niet online
PHP maakt in principe wel degelijk het niet meer benodigde geheugen vrij bij een unset en bij het verlaten van de functie scope. Daar is evenwel (nog) één belangrijke uitzondering op: circular references. Zou het kunnen dat je hier tegenaan loopt?

Oftewel: het probleem met die aangehaalde code hoeft niet te komen door een statische variabele, maar kan ook komen doordat hij een verwijzing naar zichzelf creëert, waardoor het object voor de carbage collector uiteindelijk nog in gebruikt lijkt.

Mogelijke oplossingen (in beide gevallen):
-> Moet je telkens een nieuwe instance van dompdf maken, of zou je de eerste steeds op nieuw kunnen gebruiken?
-> Je wilt de code van dompdf liever niet aanpassen, begrijpelijk. Maar staat iets je in de weg om 'm te extenden? Je kunt dan in jouw afgeleide klasse een destructor toevoegen die specifiek dit probleem aanpakt. D.w.z. als die destructor eerst die referentie naar zichzelf unset, dan zal bij het vervolgens unsetten van het object zelf ook het geheugen vrij komen. Of, als het 'm toch in een statische variabele zit, dan kan de destructor die legen en daarmee het geheugen vrijgeven.

[ Voor 16% gewijzigd door Gwaihir op 08-07-2007 16:05 ]


Acties:
  • 0 Henk 'm!

  • Gwaihir
  • Registratie: December 2002
  • Niet online
pierre-oord schreef op zondag 08 juli 2007 @ 14:07:
Ik wil gewoon die hele class in het geheugen trashen, en later roep ik (of include ik hem) dan wel weer opnieuw :)
Hij gooit altijd alleen de instanties weg. Niet de klasse (code) zelf, noch de statische variabelen die deel uitmaken van die klasse. Die laatste blijven gewoon voor je beschikbaar, rechtstreeks (als ze public zijn), via statische methods, en / of via nieuwe instanties van de klasse.

Acties:
  • 0 Henk 'm!

  • pierre-oord
  • Registratie: April 2002
  • Laatst online: 10-02 23:00
Gwaihir,

Ik zal nog eens proberen wat je zegt, zonder die class steeds opnieuw aan te roepen. Ik ben alleen bang dat er dan andere problemen optreden. Voor nu heb ik even een tijdelijke oplossing gemaakt via het extern includen, maar het maakt dingen nu al erg complex. Ik ga dit dus zsm uitproberen.

Acties:
  • 0 Henk 'm!

  • storeman
  • Registratie: April 2004
  • Laatst online: 23:07
Ik denk even in een hele andere richting, niet zozeer gefocust op het geheugen vrijmaken.

Je zou via fopen een file kunnen laten parsen, deze data ophalen en als een string in elkaar zetten en vervolgens aan een attachment plakken.

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$f = fopen("http://www.domein.nl/pleknaarpdfparser.php", "r");

$strContent = "";
while(!@feof($f))
{
   // lees de data in blokjes
   $strContent.= @fread($f, 8192);

   // Als er geen data gelezen wordt, voorkom een oneindige loop
   if($strContent == '') break;
}

// Poep het pdfje uit
header(....);

echo $strContent;


Op die manier haal je dus alleen de string, alle statics worden dan vernietigd, daar het pdf parse script gewoon stopt na 1 request.

let op dat je url_fopen_wrapper (of zoiets) aan hebt staan, anders kun je geen remote bestanden lezen, locaal gaat niet werken daar ze door je php parser getrokken moeten worden.

"Chaos kan niet uit de hand lopen"


Acties:
  • 0 Henk 'm!

  • robbert
  • Registratie: April 2002
  • Laatst online: 20:37
storeman schreef op zondag 08 juli 2007 @ 18:13:
Ik denk even in een hele andere richting, niet zozeer gefocust op het geheugen vrijmaken.

Je zou via fopen een file kunnen laten parsen, deze data ophalen en als een string in elkaar zetten en vervolgens aan een attachment plakken.

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$f = fopen("http://www.domein.nl/pleknaarpdfparser.php", "r");

$strContent = "";
while(!@feof($f))
{
   // lees de data in blokjes
   $strContent.= @fread($f, 8192);

   // Als er geen data gelezen wordt, voorkom een oneindige loop
   if($strContent == '') break;
}

// Poep het pdfje uit
header(....);

echo $strContent;


Op die manier haal je dus alleen de string, alle statics worden dan vernietigd, daar het pdf parse script gewoon stopt na 1 request.

let op dat je url_fopen_wrapper (of zoiets) aan hebt staan, anders kun je geen remote bestanden lezen, locaal gaat niet werken daar ze door je php parser getrokken moeten worden.
Dan zou ik liever met exec doen:
PHP:
1
$pdf = exec("php pdfparser.php");

Dan hoeft het niet nog eens langs de webserver.
Je moet hier wel opletten met newlines, exec geeft enkel de laatste regel terug. Als de gegenereerde pdf uit meerdere regels bestaat moet je de output parameter gebruiken

[ Voor 9% gewijzigd door robbert op 08-07-2007 18:46 ]


Acties:
  • 0 Henk 'm!

  • pierre-oord
  • Registratie: April 2002
  • Laatst online: 10-02 23:00
robbert schreef op zondag 08 juli 2007 @ 18:33:
[...]

Dan zou ik liever met exec doen:
PHP:
1
$pdf = exec("php pdfparser.php");

Dan hoeft het niet nog eens langs de webserver.
Je moet hier wel opletten met newlines, exec geeft enkel de laatste regel terug. Als de gegenereerde pdf uit meerdere regels bestaat moet je de output parameter gebruiken
Ik heb m'n probleem inderdaad nu opgelost, via passthru, niet met exec. Ik weet niet of ik de output van exec, als die in meer regels komt, wel gewoon aan elkaar mag plakken (want de output komt als array). Is die functie binary safe ofzo?

In ieder geval heb ik het nu opgelost door met ob_start, de output opvangen van passthru, en daarna de output in een string zetten. Werkt goed :) het enige is dat mensen met safemode nu wat gedoe krijgen.
Het word alleen wel minder gebruiksvriendelijk. Ik zorgde er altijd voor dat het wilde werken met safe mode, maar nu word dat moeilijker: het kan wel, maar dan moeten de gebruikers wel netjes de openbase_dir instellen, en een temponary directory opgeven.
Zonder temp. directory kan het ook werken, maar dat vereist een hoop meer code: het PDF-generate script moet dan de HTML zelf ophalen. Of weet iemand of ik als argument ook een hele HTML code kan meegeven aan passthru? Dat zou handiger zijn. Normaal kun je dat op de command line prima doen, maar dat werkt nu even anders.

Ik ga nog even wat experimenteren. In ieder geval bedankt voor alle info mbt geheugenlegen... hier mag PHP nog wel eens wat aan gaan werken. Ik las dat in PHP 6 safe-mode helemaal gaat verdwijnen trouwens... dat word nog wat.

Acties:
  • 0 Henk 'm!

  • kokx
  • Registratie: Augustus 2006
  • Laatst online: 13-09 20:30

kokx

WIN

In PHP6 gaan ze nog wel meer van dat soort geintjes uithalen. Zo verdwijnt magic_quotes, register_globals en andere *** settings die ooit onnodig ontwikkeld zijn.

Acties:
  • 0 Henk 'm!

  • Gwaihir
  • Registratie: December 2002
  • Niet online
Hmm.. hebben safe mode gebruikers dan doorgaans wel passthru en CLI PHP tot hun beschikking, dan wel allow_url_fopen aan staan voor die fopen truc?

Safe mode is altijd een moeizame bedoening geweest. Ik vermoed dat breder gebruik van php in cgi mode ervoor in de plaats komt. (Fast-)cgi heeft inmiddels voldoende volwassen performance om dat mogelijk te maken :).

M.b.t. geheugen legen: als je probleem met een static variabele samenhangt, dan gebruikt de dompdf schrijver die op een onverstandige manier en kun je hem / haar het beste daar even op wijzen. Zit het in zo'n cirkel-verwijzing, dan put ik uit dat artikel waar ik naar linkte alle hoop dat het in de loop van dit jaar wel gefixt wordt.
Pagina: 1