Блог Валентина Удальцова о разработке на PHP.
Хобот @phpyhobot
https://youtube.com/@phpyh
https://vkvideo.ru/@phpyh
https://t.me/isPHPdying
Статистика: https://t.me/INOTAROBOT?start=st1219340804
Для связи используйте личные сообщения канала.
Post #431
7.4K
Enum и память
Вчера мне стало интересно, в какой момент инстанциируются кейсы enum. При декларации или лениво? Логично второе, но я решил проверить при помощи скрипта:
Тут видно, что сразу после декларации енама
Но что-то мне подсказало перепроверить результат. Для этого я сгенерировал "мегаенам" на 60к кейсов, а затем все их запросил, измерив память до и после (скрипт):
И тут я сильно удивился. Потребление памяти не то что выросло, оно упало!!! Не долго думая, я написал Ilija Tovilo, автору PHP RFC: Enumerations. Вот его ответ:
Enums are generally instantiated when accessed, as you expected. The reason why the memory actually decreases was not obvious to me so I had to take a look. Before enums are instantiated, they have a pseudo-representation. That is, an AST node that contains the name of the enum case and its value if the enum is backed. Once that enum case is instantiated the name and value are copied from the pseudo AST node to the actual object, and the AST node is freed. And it turns out that the AST node actually requires more space than the object itself. If you use opcache this won't be the case, because the AST node is stored in shared memory (assuming you don't use eval), whereas the object lives in "userspace".
Выходит, что кейс enum действительно инстанциируется при обращении. Вот только в этот момент ещё и высвобождается псевдо-AST представление этого кейса, а так как оно тяжелее объекта, потребление памяти сокращается.
Вчера мне стало интересно, в какой момент инстанциируются кейсы enum. При декларации или лениво? Логично второе, но я решил проверить при помощи скрипта:
enum A
{
case X;
}
var_dump(spl_object_id(new stdClass())); // int(1)
var_dump(spl_object_id(A::X)); // int(1)
var_dump(spl_object_id(new stdClass())); // int(2)
Тут видно, что сразу после декларации енама
A::X не инстанциировался, так как новому объекту был выдан идентификатор 1. А вот при обращении A::X кейс уже завис в памяти, и следующий объект получил идентификатор 2. Короче, логичное вроде бы верно.Но что-то мне подсказало перепроверить результат. Для этого я сгенерировал "мегаенам" на 60к кейсов, а затем все их запросил, измерив память до и после (скрипт):
$code = 'enum Mega {';
for ($i = 0; $i < 60_000; ++$i) {
$code .= "case C{$i};";
}
$code .= '}';
eval($code);
unset($code);
var_dump(memory_get_usage() / 1024 / 1024); // 14.9
for ($i = 0; $i < 60_000; ++$i) {
constant("Mega::C{$i}");
}
var_dump(memory_get_usage() / 1024 / 1024); // 13.1 😳
И тут я сильно удивился. Потребление памяти не то что выросло, оно упало!!! Не долго думая, я написал Ilija Tovilo, автору PHP RFC: Enumerations. Вот его ответ:
Enums are generally instantiated when accessed, as you expected. The reason why the memory actually decreases was not obvious to me so I had to take a look. Before enums are instantiated, they have a pseudo-representation. That is, an AST node that contains the name of the enum case and its value if the enum is backed. Once that enum case is instantiated the name and value are copied from the pseudo AST node to the actual object, and the AST node is freed. And it turns out that the AST node actually requires more space than the object itself. If you use opcache this won't be the case, because the AST node is stored in shared memory (assuming you don't use eval), whereas the object lives in "userspace".
Выходит, что кейс enum действительно инстанциируется при обращении. Вот только в этот момент ещё и высвобождается псевдо-AST представление этого кейса, а так как оно тяжелее объекта, потребление памяти сокращается.
- 🤯 64
- 🔥 38
- 👍 24
- ❤ 4

