Как работает PHP "под-капотом"

Как работает PHP под капотом: управление памятью, Garbage Collector и OPcache

PHP — это один из самых популярных языков программирования для веб-разработки. Однако многие разработчики не задумываются, как именно PHP управляет памятью, выполняет код и оптимизирует свою работу. В этой статье мы разберем ключевые механизмы PHP, такие как управление памятью, Copy-on-Write (COW), Garbage Collector (GC) и OPcache. Это поможет вам писать более эффективный и оптимизированный код.

Как PHP выполняет код

PHP — это интерпретируемый язык, но перед выполнением код проходит несколько этапов обработки:

  1. Лексический анализ (Tokenization) – код разбивается на токены.
  2. Синтаксический анализ (Parsing) – из токенов строится AST (Abstract Syntax Tree).
  3. Компиляция в OP-код (Opcode) – AST компилируется в машинно-независимые инструкции.
  4. Исполнение OP-кода – Zend Virtual Machine выполняет скомпилированный код.

Этот процесс позволяет PHP быстро обрабатывать и выполнять код, а OPcache помогает ускорять выполнение, кэшируя скомпилированный байт-код.

Где хранятся переменные в памяти

PHP использует Zend Memory Manager для управления памятью. Переменные могут храниться в разных частях памяти:

Stack (Стек)

Используется для хранения локальных переменных и аргументов функций. Когда функция вызывается, её переменные записываются в стек. Когда функция завершает выполнение, её стек очищается. Работает по принципу LIFO (Last In, First Out).

Heap (Куча)

Используется для хранения объектов, массивов и динамических данных. Когда переменная создаётся, Zend Memory Manager выделяет под неё место в куче. PHP использует сборщик мусора (Garbage Collector) для очистки неиспользуемых данных.

Data Segment (Сегмент данных)

Глобальные переменные ($GLOBALS) хранятся в этом сегменте, пока скрипт выполняется.

Опкоды (OpCode Cache)

PHP-код компилируется в OP-код (байт-код), который кэшируется в OPcache. Это позволяет ускорить выполнение скрипта, так как компиляция происходит один раз.

Copy-on-Write (COW)

Copy-on-Write (COW) — это оптимизация памяти, которая позволяет уменьшить количество копий переменных в памяти, пока они не изменяются.

Как это работает:

  1. Когда переменная копируется ($b = $a), PHP не создаёт новую копию данных сразу.
  2. Оба значения ссылаются на одну и ту же область памяти.
  3. Если одна из переменных изменяется, PHP создаёт новую копию данных и изменяет её.

Пример:

$a = "Hello"; 
$b = $a; // Одна и та же ссылка в памяти

$b .= " World"; // Теперь создаётся копия, так как данные изменяются

echo $a; // "Hello"
echo $b; // "Hello World"

При этом можно проверить работу COW через debug_zval_dump():

$a = "Hello";
$b = $a; 

debug_zval_dump($a); 
// string(5) "Hello" refcount(2)

$b .= " World"; 

debug_zval_dump($a); 
// string(5) "Hello" refcount(1)

Garbage Collector (GC)

Garbage Collector (GC) в PHP отвечает за автоматическое освобождение памяти от неиспользуемых объектов. PHP использует механизм счётчика ссылок (Reference Counting), но иногда это приводит к циклическим ссылкам, которые GC должен убирать.

Как работает счётчик ссылок

Каждая переменная в PHP имеет счётчик ссылок, который показывает, сколько переменных указывают на один и тот же объект.

Пример:

$a = "Hello"; 
$b = $a; // refcount = 2
unset($a); // refcount = 1
unset($b); // refcount = 0 -> переменная удаляется из памяти

Когда refcount = 0, PHP автоматически удаляет объект из памяти.

Проблема циклических ссылок

Счётчик ссылок не может очистить циклические ссылки, где объекты ссылаются друг на друга.

Пример:

class Node {
    public $child;
}

$a = new Node();
$b = new Node();

$a->child = $b;
$b->child = $a; // Циклическая ссылка

unset($a);
unset($b);

// Переменные удалены, но память не освобождена

Как работает Garbage Collector

GC в PHP решает проблему циклических ссылок. Он:

  1. Ищет циклические ссылки.
  2. Проверяет, можно ли удалить объекты.
  3. Очищает память.

Запуск GC вручную:

gc_collect_cycles();

OPcache

OPcache — это механизм кэширования, который ускоряет выполнение PHP-кода, сохраняя скомпилированный байт-код в оперативной памяти.

Как работает OPcache

  1. PHP-файл загружается → PHP компилирует его в OP-код.
  2. OP-код сохраняется в OPcache (в оперативной памяти).
  3. При следующем вызове файла OPcache загружает байт-код из памяти, а не компилирует заново.
  4. Это значительно ускоряет выполнение.

Включение OPcache

Чтобы включить OPcache, нужно в php.ini прописать:

opcache.enable=1
opcache.memory_consumption=128
opcache.max_accelerated_files=10000
opcache.validate_timestamps=1
opcache.revalidate_freq=2

Проверка работы OPcache

Проверить, работает ли OPcache:

phpinfo();

Или:

print_r(opcache_get_status());

Очистка OPcache вручную

Если код изменился, но OPcache использует старую версию, его можно сбросить:

opcache_reset();

Вывод

PHP использует эффективные механизмы управления памятью для оптимизации работы:

  • Copy-on-Write (COW) снижает расход памяти, создавая копию данных только при их изменении.
  • Garbage Collector (GC) очищает неиспользуемые циклические ссылки.
  • OPcache ускоряет выполнение PHP-кода, кэшируя его в оперативной памяти.

Понимание этих механизмов помогает писать более оптимизированный код и эффективно управлять памятью в PHP.

Recent blogs
Структурные паттерны в программировании

Структурные паттерны в программировании

Порождающие паттерны в программировании

Порождающие паттерны в программировании

Генераторы и итераторы в PHP

Генераторы и итераторы в PHP

Объектно-ориентированное программирование в PHP

Объектно-ориентированное программирование в PHP

Структуры данных в PHP

Структуры данных в PHP