[PHP] levensduur objecten

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • winkbrace
  • Registratie: Augustus 2008
  • Laatst online: 24-08 15:17
Ik heb een webpage waarin ik de inhoud van de pagina deels laat bepalen door een Content object dat ik heb geschreven. Wanneer een andere pagina wordt geopend, wordt een nieuw Content object voor die nieuwe pagina aangemaakt.

Nu vraag ik mij af hoe lang die objecten eigenlijk blijven bestaan. Is het zo dat elke keer wanneer de pagina volledig geladen is, het object verdwijnt? Of na een bepaalde tijd misschien?
En is er nog verschil tussen PHP4 en PHP5 ivm eventuele garbage-collectors bijvoorbeeld?

Acties:
  • 0 Henk 'm!

  • Icelus
  • Registratie: Januari 2004
  • Niet online
Elke pagina krijgt een eigen stuk geheugen toegewezen. Aan het eind wordt dit weer vrijgegeven dus eventuele nog bestaande objecten worden automatisch vernietigd.

Developer Accused Of Unreadable Code Refuses To Comment


Acties:
  • 0 Henk 'm!

  • Deikke
  • Registratie: Juni 2004
  • Laatst online: 06:44
Volgens mij is het in PHP zo dat de objecten worden opgeruimd aan het einde van het script. Of als het aantal referenties (geen variabelen meer) op 0 is en de garbage collector wordt uitgevoerd (dit gebeurt denk ik niet eens bij snel geladen pagina's). Dus ja, je maakt zowieso een nieuw object aan elke keer, en deze wordt verwijderd zodra de pagina klaar is.

Acties:
  • 0 Henk 'm!

  • winkbrace
  • Registratie: Augustus 2008
  • Laatst online: 24-08 15:17
Het is me helder. Hartelijk dank voor de uitleg. :)
Dan ga ik nu eens uitzoeken hoe PHP omgaat met geheugengebruik. ;)

Acties:
  • 0 Henk 'm!

  • doeternietoe
  • Registratie: November 2004
  • Laatst online: 20-09 17:02
Waar je rekening mee moet houden is dat programmeren met PHP fundamenteel verschilt van programmeren met C++/Java en de meeste programmeertalen. Bij elke aanroep wordt in principe vanuit het oogpunt van de programmeur een nieuw proces gestart met eigen geheugen en dat proces wordt bij het einde van de aanroep en het antwoord weer vernietigd.

Het is mogelijk om objecten in sessies op te slaan zodat ze bij een volgende aanroep weer beschikbaar zijn. Dit brengt echter veel nadelen met zich mee. Er kan bijvoorbeeld onvoorspelbaar gedrag optreden als er een klasse gewijzigd is en er nog objecten van de oude klasse bestaan. Deze werkwijze is dus niet aan te raden en meestal ook niet nodig.

Voor zover ik weet ruimt PHP vrij netjes de oude geheugenresten op. Je kunt eventueel wat helpen door een goed gebruik van destructors en het afsluiten van bijvoorbeeld database connecties op het juiste moment. Er kan dan al geheugen worden vrijgegeven tijdens de aanroep. Ook zou het proces moeten stoppen als de gebruiker de verbinding verbreekt. Bij veel PHP applicaties is dat niet het geval.

Acties:
  • 0 Henk 'm!

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

.oisyn

Moderator Devschuur®

Demotivational Speaker

Deikke schreef op dinsdag 03 maart 2009 @ 14:35:
Volgens mij is het in PHP zo dat de objecten worden opgeruimd aan het einde van het script. Of als het aantal referenties (geen variabelen meer) op 0 is en de garbage collector wordt uitgevoerd (dit gebeurt denk ik niet eens bij snel geladen pagina's).
PHP heeft geen fysieke GC. Het maakt gewoon gebruik van refcounting, en zodra een refcount 0 wordt wordt meteen het object opgeruimd. Dit betekent ook dat als twee objecten naar elkaar wijzen hun refcount nooit op 0 zal gaan, en die objecten dus pas aan het eind van het script worden opgeruimd (als in, hun destructor wordt aangeroepen) en nooit eerder. Ook moet je er rekening mee houden dat bij dergelijke objecten je dus referenties kunt hebben naar objecten die al gedestruct zijn. Op zich niet erg want het fysieke object bestaat nog, maar dus wel al in een gedestructe staat.

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.


Acties:
  • 0 Henk 'm!

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

Janoz

Moderator Devschuur®

!litemod

doeternietoe schreef op dinsdag 03 maart 2009 @ 17:57:
Het is mogelijk om objecten in sessies op te slaan zodat ze bij een volgende aanroep weer beschikbaar zijn.
Eigenlijk kun je niet spreken van het opslaan van de objecten in de sessie, zeker niet wanneer je het met andere omgevingen vergelijkt. Aan het einde van het request wordt de inhoud van de sessie geserialiseerd en weggeschreven en later weer ingeladen bij een volgend request. Bij php wordt dus enkel de serialiseerbare data bewaard. Dat is ook de reden waarom je in een php sessie ook geen dingen als een socket, database verbinding of een filehandle op kunt slaan. Bij andere omgevingen blijft het object gewoon 'leven'.

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!

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

NMe

Quia Ego Sic Dico.

Janoz schreef op dinsdag 03 maart 2009 @ 18:52:
[...]

Eigenlijk kun je niet spreken van het opslaan van de objecten in de sessie, zeker niet wanneer je het met andere omgevingen vergelijkt. Aan het einde van het request wordt de inhoud van de sessie geserialiseerd en weggeschreven en later weer ingeladen bij een volgend request. Bij php wordt dus enkel de serialiseerbare data bewaard. Dat is ook de reden waarom je in een php sessie ook geen dingen als een socket, database verbinding of een filehandle op kunt slaan. Bij andere omgevingen blijft het object gewoon 'leven'.
Daar moet wel bij gezegd worden dat het wél enigszins geautomatiseerd weer gereanimeerd kan worden met behulp van de magic methods __sleep en __wakeup. :)

'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.


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
doeternietoe schreef op dinsdag 03 maart 2009 @ 17:57:
Waar je rekening mee moet houden is dat programmeren met PHP fundamenteel verschilt van programmeren met C++/Java en de meeste programmeertalen. Bij elke aanroep wordt in principe vanuit het oogpunt van de programmeur een nieuw proces gestart met eigen geheugen en dat proces wordt bij het einde van de aanroep en het antwoord weer vernietigd.
Dat is gedeeltelijk ook waar voor omgevingen als Asp.NET en JSP, en is eigenlijk meer beïnvloed door het stateless principe van HTTP.
Janoz schreef op dinsdag 03 maart 2009 @ 18:52:
Bij andere omgevingen blijft het object gewoon 'leven'.
Ook bij andere omgevingen moet je daar mee oppassen, als je in Asp.NET bijvoorbeeld gebruik maakt van een state-server worden de object ook gewoon ge-(de)serializeerd. JSP zal vast ook iets dergelijks kennen om server-farms te ondersteunen.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

(jarig!)
Woy schreef op dinsdag 03 maart 2009 @ 20:07:
Ook bij andere omgevingen moet je daar mee oppassen, als je in Asp.NET bijvoorbeeld gebruik maakt van een state-server worden de object ook gewoon ge-(de)serializeerd. JSP zal vast ook iets dergelijks kennen om server-farms te ondersteunen.
Ik vind het zelfs vrij eng klinken om resources via sessies ongedefinieerd lang en een ongedefinieerd aantal ervan open te laten zijn. Zeker met sockets, verbindingen databases en file handles moet je daar erg mee oppassen lijkt me zo. Het is tenslotte niet zo dat je de garantie krijgt dat een gebruiker weer terugkeert of nog even laat weten dat ie het voor gezien houdt, zodat je goed kan voorspellen dat bepaalde resources opgeruimd of vrijgegeven kunnen worden.

Wel kan het nuttig zijn om bepaalde zaken een langer leven te geven, terwijl je bij PHP eigenlijk altijd objecten uit een of andere serialized omgeving zult moeten halen (memcached en locale cachende omgevingen serializen doorgaans ook) als ze langer moeten blijven "leven" en dus ook "gedeelde" resources in principe altijd opnieuw aangemaakt moeten worden (vandaar ook dat MySQL zo goed aansluit bij PHP, die heeft een bijzonder goedkope verbindingscall).
Icelus schreef op dinsdag 03 maart 2009 @ 14:33:
Elke pagina krijgt een eigen stuk geheugen toegewezen. Aan het eind wordt dit weer vrijgegeven dus eventuele nog bestaande objecten worden automatisch vernietigd.
Eigenlijk is het iets meer omgekeerd, een pagina heeft voor elk nieuw stukje data ruimte nodig en dat wordt dan voor die pagina gereserveerd (tot de memory_limit wordt gehaald). Binnen die geheugenruimte kan je wat sturen met het aanroepen van unset en/of het overschrijven van waarden, maar uiteindelijk wordt het inderdaad allemaal weer weggegooid als de complete pagina-request is verwerkt.
doeternietoe schreef op dinsdag 03 maart 2009 @ 17:57:
Het is mogelijk om objecten in sessies op te slaan zodat ze bij een volgende aanroep weer beschikbaar zijn. Dit brengt echter veel nadelen met zich mee. Er kan bijvoorbeeld onvoorspelbaar gedrag optreden als er een klasse gewijzigd is en er nog objecten van de oude klasse bestaan. Deze werkwijze is dus niet aan te raden en meestal ook niet nodig.
Veel nadelen? Je moet zeker oppassen met serialized objecten (maar dat moet je in elke omgeving), maar afgezien daarvan hoeft een sessie-systeem niet echt nadelen te hebben, zolang je maar weet wat je doet en je rekening houdt met het feit dat alle data in je sessie steeds opnieuw serialized en unserialized zal worden.
Ook zou het proces moeten stoppen als de gebruiker de verbinding verbreekt. Bij veel PHP applicaties is dat niet het geval.
Daar hebben PHP-applicaties zelf, vziw, bijzonder weinig invloed op. Tenzij ze allemaal structureel ignore_user_abort() aanroepen, maar zelfs dan zullen ze over het algemeen wel een keer eindigen, zij het wat later dan de verbroken verbinding.
PHP is verder inderdaad zo opgezet dat het verbindingen die je open hebt laten staan uiteindelijk ook wel sluit voor ie helemaal stopt.

Acties:
  • 0 Henk 'm!

  • Peter
  • Registratie: Januari 2005
  • Laatst online: 13-09 17:10
.oisyn schreef op dinsdag 03 maart 2009 @ 18:10:
[...]

PHP heeft geen fysieke GC. Het maakt gewoon gebruik van refcounting, en zodra een refcount 0 wordt wordt meteen het object opgeruimd. Dit betekent ook dat als twee objecten naar elkaar wijzen hun refcount nooit op 0 zal gaan, en die objecten dus pas aan het eind van het script worden opgeruimd (als in, hun destructor wordt aangeroepen) en nooit eerder. Ook moet je er rekening mee houden dat bij dergelijke objecten je dus referenties kunt hebben naar objecten die al gedestruct zijn. Op zich niet erg want het fysieke object bestaat nog, maar dus wel al in een gedestructe staat.
Sinds PHP 5.3 is er een garbage collector aanwezig in een nieuwe revisie van de Zend Engine, welke echter wel door de gebruiker aangezet moet worden (gc_enable). Deze lost het probleem op wanneer twee objecten naar elkaar verwijzen terwijl de parent-objects geen referenties meer hebben; het is een circulaire manier van refcounten. In degelijke scripts zou dit niet veel mogen voorkomen, maar zoals bekend is het meerendeel van de geschreven PHP scripts niet als "degelijk" te bestempelen.

Sowieso is garbage collecting niet echt belangrijk voor gewone webpagina's. Zorg dat je imagedestroy aanroept na een imagecreatetruecolor, curl/socket's goed sluit, etcetera. Als je alles netjes afsluit wat geopend kan worden dan heb je nergens last van, iets wat duidelijk in de documentatie op php.net naar voren komt.

Anderzijds is het voor scripts die langer draaien wel wenselijk. Zelf heb ik een hele reeks aan projecten in PHP welke eigenlijk continu draaien: IRC Bots, synchronisatie servers en de laatste paar maanden zelfs DNS- en HTTP daemons. In dergelijke projecten kan er altijd sprake zijn van circulaire referenties, in welk geval je met de garbage collecting functies dit geheugen vrij kan maken.

[ Voor 1% gewijzigd door Peter op 04-03-2009 10:58 . Reden: toevoeging wegens (juiste) opmerking Woy ]


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Peter schreef op dinsdag 03 maart 2009 @ 22:49:
[...]
In degelijke scripts zou dit niet veel mogen voorkomen, maar zoals bekend is het meerendeel van de geschreven PHP scripts niet als "degelijk" te bestempelen.
Ik zie niet wat er mis is met twee objecten die naar elkaar verwijzen? Je ziet ze wel vaker langskomen, als je bijvoorbeeld een doubly linked list implementeert heb je het al. Ik zou dat niet meteen als "Niet degelijk" bestempelen.

[ Voor 11% gewijzigd door Woy op 03-03-2009 22:57 ]

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • Peter
  • Registratie: Januari 2005
  • Laatst online: 13-09 17:10
Mee eens, maar het gaat hier specifiek om circular references die verder niet gebruikt worden. Neem dit voorbeeld;

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
class foo {}

function bar ()
{
    $a = new foo;
    $b = new foo;
    $a -> prop = $b;
    $b -> prop = $a;
}

for ($i = 0; $i < 1000; $i++)
    bar ();
?>


$a en $b in de bar () functie worden verder nergens meer gebruikt, echter zijn ze referenties naar elkaar dus worden ze door de refcounter in PHP <5.3 niet verwijderd. Het geheugengebruik is dan ook oplopend, het begint bij 320720 en eindigd op 720448. Dit terwijl de classes nergens gebruikt worden, sterker nog, ze kunnen niet eens meer gebruikt worden.

In PHP 5.3 kan dit met de garbage collector opgelost worden door zo nu en dan gc_collect_cycles () aan te roepen. Zou je deze functie call onderin de bar () functie toevoegen, dan blijft het geheugen ten alle tijden op 320720 bytes. Hij ziet dat de referenties er inderdaad wel zijn, maar dat de parent van de referenties ($a en $b in dit geval) zelf geen referenties meer hebben, en dus logischerwijs niet meer gebruikt kunnen worden. Dit wordt door PHP een circular reference genoemd, en opgeruimt.

Bij een DLL (SplDoublyLinkedList of eigen implementatie) blijf je toegang hebben tot de eigenlijke lijst, wat anders is dan de $a/$b variablen in het voorbeeld van mij.

Ondanks dat het een stomme fout lijkt, komt het in grotere scripts (veel te) vaak voor, met name in OOP structuren geimplementeerd door iemand die niet super bekend is met de concepten.

[ Voor 6% gewijzigd door Peter op 03-03-2009 23:07 ]


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Ik reageer ook niet op het feit dat het geheugen lekt of niet, maar op het feit dat je zegt dat circular refferences in een degelijk script niet voorkomen.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”

Pagina: 1