[PHP] Geheugenlek achterhalen

Pagina: 1
Acties:

Onderwerpen


  • st0p
  • Registratie: April 2004
  • Laatst online: 19-07-2024
Ik zit met volgende probleem:

Een langdurig script wat op onze productie server draait, lekt volgens het top commando geheugen. Na verloop van tijd is volgens top ruim 90% van het geheugen in gebruik en wordt de server ook extreem traag. Ik heb in het script zelf al een ini_set("memory_limit", "128M"); opgenomen en in php.ini staat deze waarde op 16M. Het script blijft vrolijk doordraaien, terwijl hij er dus wegens een gebrek aan geheugen (server bevat 8 GB geheugen) er uit zou moeten klappen. De waarden van memory_get_peak_usage() blijven na een paar minuten draaien (script is twee uur bezig) constant, en ver onder het gebruik wat top aangeeft. Op een ubuntu 10.10 VM blijft het gebruik volgens top ook constant en ook op een ubuntu 10.04.1 x64 blijft het keurig constant. Dit brengt mij tot de conclusie dat het toch echt aan PHP of een van de vele onderliggende libraries moet liggen, nadat ik heel lang heb gezocht en gespit in mijn eigen php code. Het alternatief is dat top kaopt is, maar die kans acht ik erg klein.

Heeft iemand enig idee of er tools zijn om te kijken achterhalen wat er nou precies geheugen loopt te lekken?

De server waarop het fout gaat is een ubuntu 9.10 (niet mijn keuze) x64 instalatie die volledig bijgewerkt is met apt-get update en apt-get upgrade.

  • Hipska
  • Registratie: Mei 2008
  • Laatst online: 15-09 21:08
Ten eerste is php niet echt geschikt om langdurig te draaien, maar zoals de naam aangeeft om html pagina's te preprocessen.

Daarnaast geef je ook niet mee welke versie php het hier gaat.

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Hipska schreef op donderdag 16 december 2010 @ 14:26:
Ten eerste is php niet echt geschikt om langdurig te draaien, maar zoals de naam aangeeft om html pagina's te preprocessen.
Dat PHP's oorsprong puur op het web gericht is wil niet zeggen dat je het niet ook op de commandline kan gebruiken. Ik stel dus voor dat je dergelijke opmerkingen onderbouwt met echte argumenten in plaats van alleen de naamgeving aan te halen. ;)

Ontopic: geen idee eigenlijk. Het klinkt alsof je een buggende versie van PHP hebt geïnstalleerd op je productieserver. Welke versies heb je op productie en development draaien?

[ Voor 15% gewijzigd door NMe op 16-12-2010 14:36 ]

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


  • Koetjeboe
  • Registratie: Maart 2002
  • Laatst online: 20-09 21:46

Koetjeboe

Boe, zegt de koe

Als op de ubuntu 10.10 php 5.3 of groter draait en op de productie server een php versie onder de 5.3 zou het goed iets met deze http://bugs.php.net/bug.php?id=33595 bug te maken kunnen hebben...hebben wij ook veel last van gehad.

Ik zie dat ubuntu 9.10 standaard PHP 5.2.10 draait, dus als je veel objecten gebruikt zou ik bovenstaande eens goed bekijken.

[ Voor 21% gewijzigd door Koetjeboe op 16-12-2010 14:43 ]


  • djluc
  • Registratie: Oktober 2002
  • Laatst online: 14:28
Is het een groot script wat vanalles doet? Als debugging zou je kleine losse modules e.d. moeten maken. Sowieso is zo'n groot script vaak een lastige om te beheren. Zeker met vele externe modules e.d. Kan je het proces niet opsplitsen en stuk voor stuk testen o.i.d?

  • Kalentum
  • Registratie: Juni 2004
  • Nu online
st0p schreef op donderdag 16 december 2010 @ 13:24:

Heeft iemand enig idee of er tools zijn om te kijken achterhalen wat er nou precies geheugen loopt te lekken?
Ja, xdebug. Hier zit een functie in die alle functie calls logt en ook het geheugengebruik, bv
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
<?php

xdebug_start_trace('/tmp/trace');

function doSomething($array) {
        $array[] = imagecreate(800,800);
        return $array;
}

$array = array();
for($i = 0; $i < 10; ++$i) {
        $array = doSomething($array);
}


levert een file '/tmp/trace.xt' op:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
TRACE START [2010-12-16 13:39:10]
    0.0247     325212     +168     -> doSomething() /tmp/trace.php:12
    0.0248     325296      +84       -> imagecreate() /tmp/trace.php:6
    0.0438    1631884 +1306588     -> doSomething() /tmp/trace.php:12
    0.0439    1631968      +84       -> imagecreate() /tmp/trace.php:6
    0.0761    2938556 +1306588     -> doSomething() /tmp/trace.php:12
    0.0761    2938640      +84       -> imagecreate() /tmp/trace.php:6
    0.0872    4245228 +1306588     -> doSomething() /tmp/trace.php:12
    0.0873    4245312      +84       -> imagecreate() /tmp/trace.php:6
    0.0964    5551900 +1306588     -> doSomething() /tmp/trace.php:12
    0.0965    5551984      +84       -> imagecreate() /tmp/trace.php:6
    0.1108    6858572 +1306588     -> doSomething() /tmp/trace.php:12
    0.1109    6858656      +84       -> imagecreate() /tmp/trace.php:6
    0.1414    8165276 +1306620     -> doSomething() /tmp/trace.php:12
    0.1415    8165360      +84       -> imagecreate() /tmp/trace.php:6
    0.1585    9471948 +1306588     -> doSomething() /tmp/trace.php:12
    0.1586    9472032      +84       -> imagecreate() /tmp/trace.php:6
    0.1850   10778620 +1306588     -> doSomething() /tmp/trace.php:12
    0.1851   10778704      +84       -> imagecreate() /tmp/trace.php:6
    0.2144   12085324 +1306620     -> doSomething() /tmp/trace.php:12
    0.2146   12085408      +84       -> imagecreate() /tmp/trace.php:6
    0.2482       8200
TRACE END   [2010-12-16 13:39:10]


en dan zie je dus waar PHP veel geheugen gaat gebruiken.

Om er echt in te duiken lijkt het me nuttig om een VM met Ubuntu 9.10 te installeren en kijken of het probleem inderdaad met die specifieke pakketten heeft te maken

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

Janoz

Moderator Devschuur®

!litemod

NMe schreef op donderdag 16 december 2010 @ 14:33:
[...]

Dat PHP's oorsprong puur op het web gericht is wil niet zeggen dat je het niet ook op de commandline kan gebruiken. Ik stel dus voor dat je dergelijke opmerkingen onderbouwt met echte argumenten in plaats van alleen de naamgeving aan te halen. ;)
Ik denk dat de bewijslast andersom ligt hoor ;). De design approach die het php team genomen heeft is 'We steken niet veel energie in het garbage collecten tijdens het draaien, maar verkiezen extra snelheid en ruimen alles aan het einde wel op'. Dat werkt uitstekend voor een lifecycle die enkel een request is. Ook is het goed te doen voor kortlopende scriptjes. Maar voor lang draaiende scripts zijn er betere alternatieven.

Het is dus een afweging, gebruik je de aanwezige php code en kennis en ga je vervolgens veel energie steken in het zelf goed streamlinen van het geheugengebruik, of pak je een andere techniek (python bv) en implementeer je daar je functionaliteit op een triviale manier, waarbij je echter geen gebruik kunt maken van aanwezige kennis en code.

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


  • frickY
  • Registratie: Juli 2001
  • Laatst online: 18-09 14:42
Meest voorkomende oorzaak zijn circular references tussen objecten, die de gargage collector niet goed opruimt. mem_get_usage() zal die niet zien omdat ze wat PHP betreft vrij zijn gegeven, alleen de garbage collector heeft dat fysiek nog niet geregeld.

  • Hipska
  • Registratie: Mei 2008
  • Laatst online: 15-09 21:08
NMe schreef op donderdag 16 december 2010 @ 14:33:
[...]

Dat PHP's oorsprong puur op het web gericht is wil niet zeggen dat je het niet ook op de commandline kan gebruiken. Ik stel dus voor dat je dergelijke opmerkingen onderbouwt met echte argumenten in plaats van alleen de naamgeving aan te halen. ;)
Ik zeg toch ook nergens dat het niet mogelijk is? Ik duid gewoon aan dat het voor langdurende commandline scripts niet aan te raden is. Argumenten hiervoor zijn er genoeg te vinden op het web en hoef ik volgens mij hier nog eens te plaatsen, daar gaat het topic trouwens niet over.

Ik stel voor dat we even wachten op een reactie van de TS, met daarin welke versie van php hij gebruikt.

  • moto-moi
  • Registratie: Juli 2001
  • Laatst online: 09-06-2011

moto-moi

Ja, ik haat jou ook :w

Janoz schreef op donderdag 16 december 2010 @ 15:00:
Maar voor lang draaiende scripts zijn er betere alternatieven.
Er zijn beter alternatieven, dat be ik helemaal met je eens, maar dat php totaal niet geschikt is om langdurig te draaien is wel achterhaald denk ik. Er draaien op de servers van Tweakers.net genoeg php files als bijvoorbeeld stomp-processors, en dat werkt prima, geen geheugen verlies of andere rare dingen.

God, root, what is difference? | Talga Vassternich | IBM zuigt


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

Nee duh, het is ook niet zo dat PHP automagisch geheugen gaat lekken. Maar de GC in PHP is niets meer dan een refcounting systeem. Oftewel, als jij een $a->b hebt die naar $b wijst, en een $b->a die weer naar $a wijst, en vervolgens unset je $a en $b, dan worden die objecten in werkelijkheid nooit opgeruimd omdat hun refcount nog op 1 staat.

Je hebt dus 3 opties:
1 - nooit circular references maken (wat in de praktijk betekent: gewoon niet OO programmeren)
2 - zelf een GC implementeren die dit soort circulaire referenties opruimt
3 - een platform gebruiken waarin zaken by default al goed geregeld zijn.

[ Voor 5% gewijzigd door .oisyn op 16-12-2010 15:26 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • st0p
  • Registratie: April 2004
  • Laatst online: 19-07-2024
Het issue is ondertusen gevonden, met behulp van valgrind... Ik wist eerlijk gezegd helemaal niet dat valgrind samenging met php (had het nog nooit eerder gebruikt), maar bij het zien van de volgende output wist wat de oorzaak was (zeker omdat tijdens een profile actie met xdebug eerder deze week al aan het licht was gekomen dat tijdens een iteratie van de circa 300 er al 30.000 DateTime objecten werden aangemaakt)

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
==23846== 113,180,663 (6,409,224 direct, 106,771,439 indirect) bytes in 89,017 blocks are definitely lost in loss record 7,332 of 7,332
==23846==    at 0x4C24477: calloc (vg_replace_malloc.c:418)
==23846==    by 0x483F4F: timelib_tzinfo_ctor (in /usr/bin/php5)
==23846==    by 0x483F90: timelib_tzinfo_clone (in /usr/bin/php5)
==23846==    by 0x46854B: timelib_fill_holes (in /usr/bin/php5)
==23846==    by 0x4650DF: ??? (in /usr/bin/php5)
==23846==    by 0x46531D: zim_DateTime___construct (in /usr/bin/php5)
==23846==    by 0x693F4A: ??? (in /usr/bin/php5)
==23846==    by 0x68FC6B: execute (in /usr/bin/php5)
==23846==    by 0x6938B9: ??? (in /usr/bin/php5)
==23846==    by 0x68FC6B: execute (in /usr/bin/php5)
==23846==    by 0x6938B9: ??? (in /usr/bin/php5)
==23846==    by 0x68FC6B: execute (in /usr/bin/php5)


Toen ik wist waar ik moest zoeken, bleek er inderdaad in die versie van php een bug te zitten: http://bugs.php.net/47351

Morgenochtend in alle vroegte upgraden naar 5.3.3 dus om dit te verhelpen, gelukkig dat intern 3/4 van het team al een tijd aan het devven waren tegen 5.3, dus dat we niet alles opnieuw hoefden te testen.

Overigens gaf xdebug dus eerder de foutieve hoeveelheden geheugen terug (dezelfde als memory_get_peak_usage).

Om me even in de discussie omtrent de (on)geschikhtheid van PHP voor langlopende scripts: Ik zal niet zeggen dat het ideaal of zaligmakend is, maar als ik moet kiezen tussen een complexe serie berekeningen opnieuw implementeren in een andere taal (en daarnaast de oude de oude blijven onderhouden, want ze worden ook op andere plekken gebruikt, alleen hoeft er dan maar 1 pakket voor 1 datum te worden doorgerekend ipv ruim 300 voor 542 data, en de website even omschijven van php naar een andere taal gaat niet gebeuren) dan lijkt me de keus eenvoudig.
Pagina: 1