2013-05-14 13 views
5

Docs PHP mają do powiedzenia na temat pg_free_result():Czy pg_free_result() jest konieczne, nawet jeśli wynik wykracza poza zakres?

Funkcja ta musi być wywołana tylko jeśli zużycie pamięci podczas wykonywania skryptu jest problemem. W przeciwnym razie pamięć wyników zostanie automatycznie zwolniona po zakończeniu działania skryptu.

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

Chciałbym (być może naiwnie) oczekiwać zasób zwrócony przez wywołanie pg_query() być zbierane śmieci kiedy wykracza poza zakres.

W hipotetycznej funkcji takich jak to:

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

Czy to naprawdę konieczne, aby zadzwonić pg_free_result() na końcu?

Innymi słowy, jeśli zadzwonię do tej funkcji 1000 razy, czy zajmie ona pamięć do przechowywania wszystkich 1000 wyników?

EDYCJA: Mówię o typowym przypadku, tj. pg_connect() zamiast pg_pconnect().

+0

Zależy, czy wymuszasz nowe połączenie PG, czy połączenie jest trwałe? Jeśli używasz trwałych połączeń, [zasób może nie być GC'ed] (http://www.php.net/manual/en/language.types.resource.php). Ale dlaczego nie profilować skryptu.Napisz małą próbkę i sprawdź zużycie pamięci. Jeśli ciągle rośnie do końca skryptu, dodaj 'pg_free_result' i uruchom go ponownie ... –

+0

Jest to bardziej ogólne pytanie, niezależnie od rodzaju połączenia. Wiem, że mógłbym napisać test, ale denerwuje mnie to, że dokumentacja jest tak niejasna. Jednorazowy test odpowie na moje pytanie tylko dla jednej konkretnej platformy i wersji (PHP i/lub libpq). – Zilk

+0

Właściwie masz dobry punkt. Zmieniłem to pytanie, stwierdzając, że mówię o 'pg_connect()'. – Zilk

Odpowiedz

0

Oto wyniki moich badań:

(przed/po)

z: 631288/631384

bez: 631288/631640

Zapraszam Aby uruchomić test się z tego kod:

<?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

Nie mogę replikować wyników w przypadku użycia wymienionego w pytaniu. Zajrzyj tutaj: http://pastebin.com/ghw1PHuE – Zilk

+0

Nawiasem mówiąc, twój test wpływa bezpośrednio na użycie pamięci przez dodanie kluczy i wartości do $ memory_usage. Usuń te, a otrzymasz taki sam wynik dla/bez (plus minus kilka bajtów). – Zilk

+0

Ah tak, doszedłem do wniosku, że będzie to niewielka ilość za pomocą tablicy. Zaktualizowałem mój test i wyniki. –

1

Jak słusznie wskazuje Elias Van Ootegem prawie na pewno używają trwałego połączenia. W przypadku trwałych połączeń po zapytaniu wynik musi być kontynuowany w pamięci, ponieważ możesz chcieć zebrać z niego więcej danych (na przykład ostatni błąd).

Sprowadza się to do dobrej praktyki. Jeśli pracujesz w środowisku, w którym masz 2M dostępnej pamięci, a twój skrypt może czasami uderzyć do 0,1 M pamięci, górny limit to 20 równoczesnych połączeń wywołujących ten skrypt. Następnie kolejne żądania sieciowe będą kolejkowane lub opuszczane. Nie trzeba geniuszu, aby zdać sobie sprawę, jak bardzo podatny jest na atak DDoS.

Najlepszą praktyką jest opróżnianie pamięci, gdy tylko skończysz. Dotyczy to prawie każdego programowania lub pisania skryptów. Kiedy system jest obciążony, a popyt jest wysoki, tym więcej żądań, które można obsłużyć w całym zakresie pamięci, tym lepiej. Jeśli możesz zmniejszyć maksymalny rozmiar pamięci skryptu, możesz zwiększyć liczbę współbieżnych połączeń, które można rozsądnie próbować wywołać, a tym samym zwiększyć obciążenie, które skrypt może obsłużyć.

Idealny sposób na robienie rzeczy to wydawanie zasobów tak szybko, jak to możliwe. Tylko dlatego, że tak nie jest i wszystko wydaje się działać tak podczas testów, nie ma powodu, aby tego nie robić.

+0

Skomentowałem to w odpowiedzi Eliasa, ale ta odpowiedź została usunięta wraz z komentarzami. Podsumowując: nie, to zdecydowanie nie jest trwałe połączenie. Nie używanie parametru $ conn w pg_query tylko niejawnie używa ostatniego połączenia otwartego przez 'pg_connect()' (lub 'pg_pconnect()'). Odległe połączenia są czymś zupełnie innym. Między innymi będą utrzymywać blokady i transakcje aktywne między żądaniami HTTP (jeśli używany jest mod_php), co jest prawie zawsze niepożądane. Zamiast tego używamy PgBouncer jako puli połączeń. – Zilk

+0

Jeśli chodzi o najlepsze praktyki, PHP wykorzystuje garbage collection, co zwykle sprawia, że ​​zbędne staje się jawnie bezpłatne() zasoby. Zostaną one oznaczone do usuwania śmieci, gdy staną się niedostępne (tj. Gdy wykroczą poza zakres). Najlepszą praktyką w językach zbierania śmieci jest umożliwienie GC robienia rzeczy. Pytanie brzmiało, czy dotyczy to również zasobów wynikowych PG, które _do_ mają funkcję darmową() i z testu, który zamieściłem jako komentarz do odpowiedzi Joela, wygląda na to, że tak. Ale to tylko test, a nie oficjalnie udokumentowane zachowanie. – Zilk

Powiązane problemy