О утечках памяти

Webman — это фреймворк с постоянным использованием памяти, поэтому нам следует немного обратить внимание на ситуацию с утечкой памяти. Однако разработчикам не стоит слишком беспокоиться, поскольку утечка памяти происходит только в очень крайних условиях и легко поддается избеганию. Разработка на Webman вообще не отличается от разработки на традиционных фреймворках, и не требуется никаких дополнительных операций по управлению памятью.

Совет
Процесс monitor, встроенный в Webman, будет отслеживать использование памяти всеми процессами, и если память, используемая процессом, почти достигнет значения memory_limit, установленного в php.ini, он автоматически безопасно перезапустит соответствующий процесс, чтобы освободить память, не затрагивая бизнес-процессы.

Определение утечки памяти

С увеличением количества запросов память, используемая Webman, также безгранично увеличивается (обратите внимание — безгранично увеличивается), достигая сотен мегабайт и даже больше, что и является утечкой памяти. Если память увеличивается, но после этого больше не увеличивается, это не считается утечкой памяти.

Как правило, использование десятков мегабайт памяти процессом — это нормальная ситуация, когда процесс обрабатывает очень большие запросы или поддерживает огромное количество соединений, использование памяти отдельным процессом может достигать сотен мегабайт — это тоже вполне нормально. Эта часть памяти, использованная php, возможно, не будет полностью возвращена операционной системе. Она будет оставлена для повторного использования, поэтому может возникнуть ситуация, когда после обработки какого-то большого запроса использование памяти увеличивается, но память не освобождается — это нормально. (Вызов метода gc_mem_caches() может освободить часть свободной памяти.)

Как происходит утечка памяти

Утечка памяти происходит только при выполнении следующих двух условий:

  1. Существуют массива с долгим сроком жизни (обратите внимание — массивы с долгим сроком жизни, обычные массивы не повлияют)
  2. И этот массив с долгим сроком жизни будет безгранично увеличиваться (бизнес постоянно добавляет в него данные и никогда не очищает данные)

Если оба условия 1 и 2 одновременно выполняются (обратите внимание — одновременно выполняются), то произойдет утечка памяти. В противном случае, если ни одно из условий не выполняется или выполняется только одно из условий, это не считается утечкой памяти.

Массивы с долгим сроком жизни

В Webman массивы с долгим сроком жизни включают:

  1. Массивы с ключевым словом static
  2. Свойства массивов синглтона
  3. Массивы с ключевым словом global

Замечание
В Webman разрешено использование данных с долгим сроком жизни, но необходимо гарантировать, что данные внутри массива ограничены и количество элементов не будет безгранично увеличиваться.

Следующие примеры пояснят это.

Безгранично увеличивающийся массив с ключевым словом static

class Foo
{
    public static $data = [];
    public function index(Request $request)
    {
        self::$data[] = time();
        return response('hello');
    }
}

Массив $data, определенный с помощью ключевого слова static, является массивом с долгим сроком жизни и, как видно из примера, массив $data продолжает увеличиваться с увеличением количества запросов, что приводит к утечке памяти.

Безгранично увеличивающийся массив свойства синглтона

class Cache
{
    protected static $instance;
    public $data = [];

    public function instance()
    {
        if (!self::$instance) {
            self::$instance = new self;
        }
        return self::$instance;
    }

    public function set($key, $value)
    {
        $this->data[$key] = $value;
    }
}

Код вызова

class Foo
{
    public function index(Request $request)
    {
        Cache::instance()->set(time(), time());
        return response('hello');
    }
}

Cache::instance() возвращает синглтон класса Cache, который является экземпляром класса с долгим сроком жизни, хотя его свойство $data не использует ключевое слово static, но поскольку сам класс имеет долгий срок жизни, массив $data также является массивом с долгим сроком жизни. С увеличением количества добавляемых в массив $data данных с разными ключами, объем памяти, используемый программой, также будет расти, что приводит к утечке памяти.

Замечание
Если ключи, добавляемые в Cache::instance()->set(key, value), имеют ограниченное количество, то утечки памяти не произойдет, поскольку массив $data не увеличивается безгранично.

Безгранично увеличивающийся массив с ключевым словом global

class Index
{
    public function index(Request $request)
    {
        global $data;
        $data[] = time();
        return response($foo->sayHello());
    }
}

Массив, определенный с помощью ключевого слова global, не будет освобожден после завершения выполнения функции или метода класса, поэтому он является массивом с долгим сроком жизни; вышеуказанный код будет создавать утечку памяти с увеличением количества запросов. Аналогично, массивы, определенные внутри функции или метода с использованием ключевого слова static, также являются массивами с долгим сроком жизни; если массив будет увеличиваться безгранично, это также приведет к утечке памяти. Например:

class Index
{
    public function index(Request $request)
    {
        static $data = [];
        $data[] = time();
        return response($foo->sayHello());
    }
}

Рекомендации

Разработчикам не следует слишком беспокоиться об утечках памяти, так как они происходят крайне редко. Если это все же случится, мы можем найти проблемный участок кода с помощью нагрузочного тестирования. Даже если разработчик не найдет точку утечки, встроенный в Webman сервис monitor будет периодически безопасно перезапускать процесс, в котором произошла утечка памяти, освобождая память.

Если вы действительно хотите максимально избежать утечек памяти, вы можете следовать следующим рекомендациям.

  1. По возможности не используйте массивы с ключевыми словами global и static, если используете, убедитесь, что они не будут увеличиваться безгранично.
  2. Для незнакомых классов старайтесь не использовать синглтон, инициализируйте их с помощью ключевого слова new. Если синглтон необходим, проверьте, есть ли у него массивы с безграничным увеличением.