Nie można retrospektywnie obliczyć dokładnego śladu zmiennej, ponieważ dwie zmienne mogą dzielić to samo przydzielone miejsce w pamięci
Spróbujmy podzielić pamięć między dwiema tablicami, widzimy, że przydzielenie drugiej tablicy kosztuje połowę pamięci pierwszej. Kiedy rozbroimy pierwszą, prawie cała pamięć jest nadal zajęta 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)
Nie możemy więc wnioskować, że druga tablica zużywa połowę pamięci, ponieważ staje się fałszywa, gdy usuwamy pierwszą.
Aby uzyskać pełny obraz tego, jak alokowana jest pamięć w PHP i do czego służy, sugeruję przeczytanie następującego artykułu: Jak duże są naprawdę tablice (i wartości) PHP? (Podpowiedź: DUŻA!)
W sekcji Podstawy liczenia odniesień w dokumentacji PHP znajduje się również wiele informacji o wykorzystaniu pamięci, a odwołania liczą się do segmentu danych współdzielonych.
Przedstawione tutaj różne rozwiązania są dobre do przybliżeń, ale żadne nie poradzi sobie z subtelnym zarządzaniem pamięcią PHP.
- obliczenie nowo przydzielonej powierzchni
Jeśli chcesz nowo przydzieloną przestrzeń po przydziale, musisz użyć jej memory_get_usage()przed i po przydziale, ponieważ używanie jej z kopią daje błędny obraz 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 już istnieć wcześniej i memory_get_usage()musi być nazwana poprzednio inną, a także każdą inną funkcją.
Jeśli chcesz wywołać echo jak w powyższym przykładzie, twój bufor wyjściowy musi być już otwarty, aby uniknąć pamięci rozliczeniowej potrzebnej do otwarcia bufora wyjściowego.
- obliczenie wymaganej przestrzeni
Jeśli chcesz polegać na funkcji obliczającej wymaganą przestrzeń do przechowywania kopii zmiennej, poniższy kod zajmuje się różnymi optymalizacjami:
<?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 rozmiar nazwy zmiennej ma znaczenie w przydzielonej pamięci.
- Sprawdź swój kod !!
Zmienna ma podstawowy rozmiar zdefiniowany przez wewnętrzną strukturę C używaną w kodzie źródłowym PHP. Wielkość ta nie zmienia się w przypadku liczb. W przypadku ciągów dodawałby długość ciągu.
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, wiemy już, ile używa zmienna (w przypadku liczb i łańcuchów):
44 bajty w przypadku liczb
+ 24 bajty w przypadku łańcuchów
+ długość ciągu (łącznie z ostatnim znakiem NUL)
(te liczby 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), przydzieli również 64 dodatkowe bajty.
Więc jeśli chcesz użyć jednego z kodów na tej stronie, musisz sprawdzić, czy wynik za pomocą prostych przypadków testowych (ciągów lub liczb) jest zgodny z tymi danymi, biorąc pod uwagę wszystkie wskazania w tym poście (tablica $ _GLOBAL, pierwsze wywołanie funkcji, bufor wyjściowy, ...)