Jak określić rozmiar (rozmiar) pamięci zmiennej?

Czy istnieje funkcja w PHP (lub rozszerzenie PHP), aby dowiedzieć się, ile pamięci zużywa dana zmienna? sizeof po prostu mówi mi ilość elementów / właściwości.

memory_get_usage pomaga w tym, że daje mi rozmiar pamięci używany przez cały skrypt. Czy istnieje sposób, aby to zrobić dla pojedynczej zmiennej?

Zauważ, że jest to na maszynie deweloperskiej, więc załadowanie rozszerzeń lub narzędzi debugowania jest możliwe.

 95
Author: Piskvor, 2010-02-03

11 answers

Prawdopodobnie potrzebujesz profilera pamięci. Zebrałem informacje, ale skopiowałem ważną rzecz, która może Ci pomóc.

Jak zapewne wiesz, Xdebug zrezygnował z obsługi profilowania pamięci od 2.* wersja. Wyszukaj ciąg "usunięte funkcje" tutaj: http://www.xdebug.org/updates.php

Usunięte funkcje

Usunięto wsparcie dla profilowania pamięci, ponieważ nie działało jak należy.

Inne Opcje Profilera

Php-memory-profiler

Https://github.com/arnaud-lb/php-memory-profiler . to właśnie zrobiłem na moim serwerze Ubuntu, aby go włączyć:

sudo apt-get install libjudy-dev libjudydebian1
sudo pecl install memprof
echo "extension=memprof.so" > /etc/php5/mods-available/memprof.ini
sudo php5enmod memprof
service apache2 restart

A potem w moim kodzie:

<?php
memprof_enable();
// do your stuff
memprof_dump_callgrind(fopen("/tmp/callgrind.out", "w"));

Na koniec otwórz plik callgrind.out za pomocą KCachegrind

Korzystanie z Google gperftools (zalecane!)

Najpierw zainstaluj Google gperftools pobierając najnowszy pakiet tutaj: https://code.google.com/p/gperftools/

Wtedy jak zawsze:

sudo apt-get update
sudo apt-get install libunwind-dev -y
./configure
make
make install

Teraz w kodzie:

memprof_enable();

// do your magic

memprof_dump_pprof(fopen("/tmp/profile.heap", "w"));

Następnie otwórz terminal i uruchom:

pprof --web /tmp/profile.heap

pprof utworzy nowe okno w istniejącej sesji przeglądarki z czymś takim jak pokazano poniżej:

Profilowanie pamięci PHP za pomocą memprof i gperftools

Xhprof + Xhgui (moim zdaniem najlepszy do profilowania zarówno procesora, jak i pamięci)]}

Z Xhprofi Xhgui Możesz również profilować użycie procesora lub po prostu zużycie pamięci, jeśli to jest Twój problem w tej chwili. Jest to bardzo kompletne rozwiązanie, daje pełną kontrolę, a logi mogą być zapisywane zarówno na mongo, jak i w systemie plików.

Po Więcej Szczegółów zobacz tutaj .

Blackfire

Blackfire to PHP profiler stworzony przez SensioLabs, The Symfony2 guys https://blackfire.io/

Jeśli używasz puphpet aby skonfigurować swoją Maszynę wirtualną, będziesz zadowolony, że jest obsługiwana; -)

Xdebug i śledzenie wykorzystania pamięci

XDEBUG2 jest rozszerzeniem dla PHP. Xdebug pozwala na rejestrowanie wszystkich wywołań funkcji, w tym parametrów i wartości zwracanych do pliku w różnych formatach.Istnieją trzy formaty wyjściowe. Jeden jest rozumiany jako ślad czytelny dla człowieka, drugi jest bardziej odpowiedni dla programów komputerowych, ponieważ jest łatwiejszy do przetworzenia, a ostatni używa HTML do formatowania śladu. Możesz przełączać się między dwoma różnymi formatami za pomocą tego ustawienia. Przykładem może być dostępny tutaj

Forp

Forp prosty, nieinwazyjny, zorientowany na produkcję, profiler PHP. Niektóre z funkcji to:

  • Pomiar czasu i przydzielonej pamięci dla każdej funkcji

  • Wykorzystanie procesora

  • Plik i numer linii wywołania funkcji

  • Wyjście jako format zdarzenia śledzenia Google

  • Podpis funkcji

  • Grupowanie funkcji

  • Pseudonimy funkcje (przydatne dla funkcji anonimowych)

DBG

DBG to w pełni funkcjonalny debugger php, interaktywne narzędzie, które pomaga debugować skrypty php. Działa na serwerze produkcyjnym i / lub deweloperskim i umożliwia debugowanie skryptów lokalnie lub zdalnie, z poziomu IDE lub konsoli, a jego funkcje to:

  • Zdalne i lokalne debugowanie

  • Aktywacja Jawna i niejawna

  • Stos połączeń, w tym wywołania funkcji, dynamiczne i statyczne wywołania metod, z ich parametrami

  • Nawigacja po stosie wywołań z możliwością oceny zmiennych w odpowiednich (zagnieżdżonych) miejscach

  • Krok in/krok out/krok over / Uruchom do funkcji kursora

  • Warunkowe punkty przerwania

  • Global breakpoints

  • Rejestrowanie błędów i ostrzeżeń

  • Wiele jednoczesnych sesji dla równoległych debugowanie

  • Obsługa interfejsów GUI i CLI

  • Obsługiwane sieci IPv6 i IPv4

  • Wszystkie dane przesyłane przez debugger mogą być opcjonalnie chronione za pomocą SSL

 38
Author: Vineet1982,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:32:29

Nie ma bezpośredniego sposobu, aby uzyskać użycie pamięci pojedynczej zmiennej, ale jak zasugerował Gordon, możesz użyć memory_get_usage. Zwróci to całkowitą ilość przydzielonej pamięci, dzięki czemu można zastosować obejście i pomiar użycia przed i po, Aby uzyskać użycie pojedynczej zmiennej. To trochę trudne, ale powinno zadziałać.

$start_memory = memory_get_usage();
$foo = "Some variable";
echo memory_get_usage() - $start_memory;

Zauważ, że nie jest to w żaden sposób niezawodna metoda, nie możesz być pewien, że nic innego nie dotyka pamięci podczas przypisywania zmiennej, więc powinno to być używane tylko jako / align = "left" /

Możesz zmienić to w funkcję, tworząc kopię zmiennej wewnątrz funkcji i mierząc używaną pamięć. Nie testowałem tego, ale w zasadzie nie widzę w tym nic złego:

function sizeofvar($var) {
    $start_memory = memory_get_usage();
    $tmp = unserialize(serialize($var));
    return memory_get_usage() - $start_memory;
}
 89
Author: Tatu Ulmanen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-26 13:11:41

Nie, Nie ma. Ale możesz serialize($var) i sprawdź strlen wyniku dla przybliżenia.

 22
Author: Aistina,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-03 14:40:56

W odpowiedzi na Tatu Ulmanens odpowiedź:

Należy zauważyć, że {[1] } sama zajmie Pamięć (PHP_INT_SIZE * 8).

Więc cała funkcja powinna być:

function sizeofvar($var) {
    $start_memory = memory_get_usage();
    $var = unserialize(serialize($var));
    return memory_get_usage() - $start_memory - PHP_INT_SIZE * 8;
}

Przepraszam, że dodaję to jako dodatkową odpowiedź, ale nie mogę jeszcze skomentować odpowiedzi.

Update: *8 nie jest definiowane. Może zależeć najwyraźniej od wersji php i prawdopodobnie na 64/32 bit.

 20
Author: para,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-25 15:55:21

Zobacz:

Zauważ, że to nie pozwoli Ci na użycie pamięci określonej zmiennej. Ale można umieścić wywołania do tych funkcji przed i po przypisaniu zmiennej, a następnie porównać wartości. To powinno dać ci wyobrażenie o użytej pamięci.

Możesz też rzucić okiem na rozszerzenie PECL Memtrack , choć dokumentacji trochę brakuje, Jeśli nie powiedzieć, praktycznie nie istnieje.

 4
Author: Gordon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-29 06:57:06

Możesz zdecydować się na obliczanie różnicy pamięci na wartości zwrotnej wywołania zwrotnego. Jest to bardziej eleganckie rozwiązanie dostępne w PHP 5.3+.

function calculateFootprint($callback) {
    $startMemory = memory_get_usage();
    $result = call_user_func($callback);
    return memory_get_usage() - $startMemory;
}

$memoryFootprint = calculateFootprint(
    function() {
        return range(1, 1000000);
    }
);

echo ($memoryFootprint / (1024 * 1024)) . ' MB' . PHP_EOL;
 3
Author: Liviu Bundă,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-07 07:16:21

Nie można retrospektywnie obliczyć dokładnego footprintu zmiennej, ponieważ dwie zmienne mogą dzielić tę samą przydzieloną przestrzeń w pamięci

Spróbujmy współdzielić pamięć między dwiema tablicami, widzimy, że przydzielenie drugiej tablicy kosztuje połowę pamięci pierwszej. Kiedy wyłączamy pierwszą, prawie cała pamięć jest nadal używana przez drugą.

echo memory_get_usage()."\n"; // <-- 433200
$c=range(1,100);
echo memory_get_usage()."\n"; // <-- 444348 (+11148)
$d=array_slice($c, 1);
echo memory_get_usage()."\n"; // <-- 451040 (+6692)
unset($c);
echo memory_get_usage()."\n"; // <-- 444232 (-6808)
unset($d);
echo memory_get_usage()."\n"; // <-- 433200 (-11032)

Więc nie możemy stwierdzić, że druga tablica używa połowy pamięci, ponieważ staje się fałszywa, gdy wyłączymy pierwszy.

Aby uzyskać pełny widok jak pamięć jest przydzielana w PHP i do jakiego zastosowania, proponuję przeczytać następujący artykuł: jak duże są tablice (i wartości) PHP naprawdę? (Hint: BIG!)

Podstawy liczenia referencji w dokumentacji PHP zawiera również wiele informacji o wykorzystaniu pamięci, a odniesienia liczą się do współdzielonego segmentu danych.

Różne rozwiązania tutaj są dobre dla przybliżeń, ale żaden nie poradzi sobie z subtelnymi zarządzanie pamięcią PHP.

  1. obliczanie nowo przydzielonej przestrzeni

Jeśli chcesz nowo przydzieloną przestrzeń po przydziale, musisz użyć memory_get_usage() przed i po przydziale, ponieważ użycie jej z kopią daje błędny widok rzeczywistości.

// open output buffer
echo "Result: ";
// call every function once
range(1,1); memory_get_usage();

echo memory_get_usage()."\n";
$c=range(1,100);
echo memory_get_usage()."\n";

Pamiętaj, że jeśli chcesz zapisać wynik pierwszej memory_get_usage(), zmienna musi istnieć już wcześniej, a {[4] } musi być wywołana innym poprzednim razem, a każda inna funkcja również.

Jeśli chcesz echo jak w powyższym przykładzie, Twój bufor wyjściowy musi być już otwarty, aby uniknąć pamięci księgowej potrzebnej do otwarcia bufora wyjściowego.

  1. obliczanie wymaganej przestrzeni

Jeśli chcesz polegać na funkcji do obliczenia wymaganego miejsca do przechowywania kopii zmiennej, poniższy kod dba o różne optymalizacje:

<?php
function getMemorySize($value) {
    // existing variable with integer value so that the next line
    // does not add memory consumption when initiating $start variable
    $start=1;
    $start=memory_get_usage();
    // json functions return less bytes consumptions than serialize
    $tmp=json_decode(json_encode($value));
    return memory_get_usage() - $start;
}

// open the output buffer, and calls the function one first time
echo ".\n";
getMemorySize(NULL);

// test inside a function in order to not care about memory used
// by the addition of the variable name to the $_GLOBAL array
function test() {
    // call the function name once 
    range(1,1);

    // we will compare the two values (see comment above about initialization of $start)
    $start=1;
    $start=memory_get_usage();
    $c=range(1,100);
    echo memory_get_usage()-$start."\n";
    echo getMemorySize($c)."\n";
}
test();

// same result, this works fine.
// 11044
// 11044

Zauważ, że wielkość nazwy zmiennej ma znaczenie w pamięci / align = "left" /

  1. Sprawdź kod!!

Zmienna ma podstawowy rozmiar określony przez wewnętrzną strukturę C używaną w kodzie źródłowym PHP. Wielkość ta nie zmienia się w przypadku liczb. Dla ciągów, to dodać długość łańcucha.

typedef union _zvalue_value {
    long lval;                  /* long value */
    double dval;                /* double value */
    struct {
        char *val;
        int len;
    } str;
    HashTable *ht;              /* hash table value */
    zend_object_value obj;
} zvalue_value;

Jeśli nie weźmiemy pod uwagę inicjalizacji nazwy zmiennej, to już wiemy, ile zmienna używa (w przypadku liczb i łańcuchów):

44 bajty w przypadku liczb

& plus; 24 bajty w przypadku łańcuchów

&plus; długość łańcucha (włącznie z końcowym znakiem NUL)

(liczby te mogą się zmieniać w zależności od wersji PHP)

Musisz zaokrąglić do wielokrotności 4 bajtów ze względu na wyrównanie pamięci. Jeśli zmienna znajduje się w przestrzeni globalnej (Nie wewnątrz funkcji), przydziela również 64 bajty więcej.

Więc jeśli chcesz użyć jednego z kodów wewnątrz tej strony, musisz sprawdzić, czy wynik za pomocą prostych przypadków testowych (ciągów lub liczb) pasuje do tych danych, biorąc pod uwagę każdy z oznaczeń w tym poście (tablica$_GLOBAL, pierwsze wywołanie funkcji, bufor wyjściowy, ...)

 3
Author: Adam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-17 22:37:21

Miałem podobny problem i rozwiązaniem, którego użyłem, było zapisanie zmiennej do pliku, a następnie uruchomienie fileSize() na nim. Mniej więcej tak (Kod nieprzetestowany):

function getVariableSize ( $foo ) 
{
    $tmpfile = "temp-" . microtime(true) . ".txt";
    file_put_contents($tmpfile, $foo);
    $size = filesize($tmpfile);
    unlink($tmpfile);
    return $size;
}

To rozwiązanie nie jest zbyt szybkie, ponieważ obejmuje Disk IO, ale powinno dać ci coś znacznie dokładniejszego niż sztuczki memory_get_usage. To zależy tylko od tego, ile precyzji potrzebujesz.

 2
Author: Alan Bellows,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-30 15:47:46

Nigdy nie próbowałem, ale Xdebug łączy się z xdebug.collect_assignment S może wystarczyć.

 1
Author: Arkh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-03 15:43:05
function mesure($var){
    $start = memory_get_usage();
    if(is_string($var)){
        $newValue = $var . '';
    }elseif(is_numeric($var)){
        $newValue = $var + 0;
    }elseif(is_object($var)){
        $newValue = clone $var;
    }elseif(is_array($var)){
        $newValue = array_flip($var, []);
    }
    return memory_get_usage() - $start;
}
 1
Author: Abdelilah,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-13 11:59:58

Poniższy skrypt pokazuje całkowite zużycie pamięci pojedynczej zmiennej.

function getVariableUsage($var) {
  $total_memory = memory_get_usage();
  $tmp = unserialize(serialize($var));
  return memory_get_usage() - $total_memory; 
}

$var = "Hey, what's you doing?";
echo getVariableUsage($var);

Zobacz to

Http://www.phpzag.com/how-much-memory-do-php-variables-use/

 0
Author: vongani masanganye,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-15 09:08:43