2013-05-14 13 views
5

La documentazione PHP hanno da dire su pg_free_result():È necessario pg_free_result(), anche se il risultato non rientra nell'ambito?

Questa funzione deve essere richiamata solo se il consumo di memoria durante edizione esecuzione è un problema. In caso contrario, la memoria di tutti i risultati sarà liberata automaticamente allo al termine dello script.

http://www.php.net/manual/en/function.pg-free-result.php

avrei (forse ingenuamente) aspettato la risorsa restituito da una chiamata a pg_query() essere garbage collection quando va fuori di portata.

In una funzione ipotetica come questo:

function selectSomething() 
{ 
    $res = pg_query("SELECT blah FROM sometable"); 
    // do something with $res 
    pg_free_result($res); // required or not? 
} 

E 'davvero necessario chiamare pg_free_result() alla fine?

In altre parole, se chiamo questa funzione 1000 volte, mangerà memoria per memorizzare tutti i 1000 risultati?

MODIFICA: sto parlando del caso tipico, ovvero pg_connect() anziché pg_pconnect().

+0

Depends, stai forzando una nuova connessione pg o la connessione è persistente? Se stai usando una connessione persistente, [la risorsa potrebbe non essere GC] (http://www.php.net/manual/en/language.types.resource.php). Ma perché non delineare la sceneggiatura.Scrivi una piccola prova e controlla l'utilizzo della memoria. Se continua ad aumentare fino alla fine dello script, aggiungi 'pg_free_result', ed eseguilo di nuovo ... –

+0

Questa è più una domanda generale, indipendentemente dal tipo di connessione. So che potrei semplicemente scrivere un test, ma mi dà fastidio che la documentazione sia così vaga. Un test una tantum risponderà alla mia domanda solo per una piattaforma e una versione specifica (PHP e/o libpq). – Zilk

+0

In realtà, hai un buon punto lì. Ho modificato la domanda dichiarando che sto parlando di 'pg_connect()'. – Zilk

risposta

0

Qui ci sono i miei risultati dei test:

(prima/dopo)

con: 631288/631384

senza: 631288/631640

Sentitevi liberi di eseguire il test da soli con questo codice:

<?php 
class test { 
    private static $tests = 5000; 

    public function __construct() { 
     $dbconn = pg_connect("host=### dbname=### user=### password=###") 
      or die('Could not connect: ' . pg_last_error()); 

     self::test(self::$tests, true); 
     self::test(self::$tests, false); 
    } 

    private function test($times, $with) { 
     echo ($with ? "with:<br />\n" : "without:<br />\n") . memory_get_usage() ."<br />\n"; 

     for($i = 0; $i < $times; $i++) { 
      $res = pg_query("SELECT * FROM chowder"); 

      if($with) { 
       pg_free_result($res); 
      } 
     } 

     echo memory_get_usage() ."<br /><br />\n\n"; 
    } 

} 

$test = new test(); 
+0

Non riesco a replicare i risultati per il caso d'uso menzionato nella domanda. Guarda qui: http://pastebin.com/ghw1PHuE – Zilk

+0

A proposito, il test influenza direttamente l'utilizzo della memoria aggiungendo chiavi e valori a $ memory_usage. Rimuovi quelli e ottieni lo stesso risultato con/senza (più meno un paio di byte). – Zilk

+0

Ah, sì, ho pensato che sarebbe un importo trascurabile utilizzando la matrice. Ho aggiornato il mio test e i risultati. –

1

Come giustamente indicato da Elias Van Ootegem stanno quasi certamente usando una connessione persistente. Con le connessioni persistenti dopo la query, il risultato deve continuare in memoria perché potresti desiderare di raccogliere più dati da esso (ad esempio l'ultimo errore).

Quindi si tratta di buone pratiche. Se stai operando in un ambiente in cui hai 2M di memoria disponibile e il tuo script può, a volte, raggiungere uno 0.1M di memoria, allora il limite superiore è di 20 connessioni simultanee che chiamano quello script. Successivamente, ulteriori richieste Web verranno messe in coda o in coda. Non ci vuole un genio per rendersi conto di quanto questo possa essere vulnerabile all'attacco di DDoS.

Le migliori pratiche, quindi, è svuotare la memoria non appena ne hai finito. Questo vale per qualsiasi programmazione o script di sempre. Quando il sistema viene sollecitato e la domanda è alta, più richieste possono essere soddisfatte all'interno della portata totale della memoria, meglio è. Se è possibile ridurre il footprint di memoria massimo di uno script, è possibile aumentare il numero di connessioni simultanee che possono ragionevolmente provare a chiamarlo e quindi aumentare il carico che lo script può gestire.

Il modo ideale per fare le cose è liberare le risorse il prima possibile. Solo perché non lo facciamo e tutto sembra funzionare comunque durante i test non c'è motivo per non farlo.

+0

Ho commentato questo nella risposta di Elias, ma quella risposta è stata cancellata insieme ai commenti. Per riassumere: no, questa non è sicuramente una connessione persistente. Non usare un parametro $ conn in pg_query usa solo implicitamente l'ultima connessione aperta da 'pg_connect()' (o 'pg_pconnect()'). Le connessioni persistenti sono qualcosa di completamente diverso. Tra le altre cose, manterranno i blocchi e le transazioni attive tra le richieste HTTP (se si usa mod_php), che è quasi sempre indesiderato. Utilizziamo invece PgBouncer come pool di connessioni. – Zilk

+0

Come per le migliori pratiche, PHP usa la garbage collection, che di solito rende superflue risorse esplicitamente free(). Saranno contrassegnati per la raccolta dei rifiuti quando diventano inaccessibili (cioè quando escono dall'ambito di applicazione). La migliore pratica nelle lingue raccolte dai rifiuti consiste nel lasciare che il GC faccia il suo esempio. La domanda era se questo si applica anche alle risorse risultato PG, che _do_ hanno una funzione free(), e dal test che ho postato come commento alla risposta di Joel, sembra che lo faccia. Ma questo è solo un test, non un comportamento ufficialmente documentato. – Zilk

Problemi correlati