Ви не можете ретроспективно обчислити точний слід змінної, оскільки дві змінні можуть поділяти один і той же виділений простір у пам'яті
Спробуємо поділити пам'ять між двома масивами, бачимо, що виділення другого масиву коштує половину пам'яті першого. Коли ми скидаємо перший, майже вся пам'ять все ще використовується другою.
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)
Тому ми не можемо зробити висновок, що другий масив використовує половину пам'яті, оскільки він стає помилковим, коли ми скидаємо перший.
Для повного перегляду того, як розподіляється пам'ять у PHP та для якого використання, пропоную прочитати наступну статтю: Наскільки насправді масиви (та значення) PHP є великими? (Підказка: ВЕЛИКИЙ!)
В Основах підрахунку посилань в документації PHP також має багато інформації про використання пам'яті, а також підраховувати посилання на розділяється сегмент даних.
Тут розкриваються різні рішення, які корисні для наближення, але жодне не може впоратися з тонким керуванням пам'яттю PHP.
- розрахунок щойно виділеного простору
Якщо ви хочете, щоб після призначення було виділено простір після призначення, вам доведеться використовувати його memory_get_usage()
до і після розподілу, оскільки використання його з копією дає помилковий погляд на реальність.
// 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";
Пам'ятайте, що якщо ви хочете зберегти результат першого memory_get_usage()
, змінна повинна існувати і раніше, і memory_get_usage()
повинна бути викликана іншим попереднім часом, і всі інші функції також.
Якщо ви хочете лунати, як у наведеному вище прикладі, ваш вихідний буфер повинен бути вже відкритим, щоб уникнути пам'яті обліку, необхідної для відкриття вихідного буфера.
- розрахунок необхідного місця
Якщо ви хочете покластися на функцію для обчислення необхідного простору для зберігання копії змінної, наступний код має на увазі різні оптимізації:
<?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
Зауважте, що розмір імені змінної має значення у виділеній пам'яті.
- Перевір свій код !!
Змінна має базовий розмір, визначений внутрішньою структурою С, що використовується у вихідному коді PHP. Цей розмір не коливається у випадку чисел. Для рядків це додало б довжину рядка.
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;
Якщо ми не беремо до уваги ініціалізацію імені змінної, ми вже знаємо, скільки використовує змінна (у випадку чисел та рядків):
44 байти у випадку чисел
+ 24 байти у разі рядків
+ довжина рядка (включаючи кінцевий символ NUL)
(ці цифри можуть змінюватися залежно від версії PHP)
Через вирівнювання пам’яті вам потрібно округлювати до кратного 4 байти. Якщо змінна знаходиться у глобальному просторі (а не всередині функції), вона також виділить ще 64 байти.
Отже, якщо ви хочете використовувати один з кодів на цій сторінці, ви повинні перевірити, чи результат, використовуючи прості тестові випадки (рядки чи цифри), відповідає цим даним, беручи до уваги кожне із показань у цій публікації (масив $ _GLOBAL, перший виклик функції, буфер виводу, ...)