О утечках памяти
Webman — это фреймворк с постоянным использованием памяти, поэтому нам следует немного обратить внимание на ситуацию с утечкой памяти. Однако разработчикам не стоит слишком беспокоиться, поскольку утечка памяти происходит только в очень крайних условиях и легко поддается избеганию. Разработка на Webman вообще не отличается от разработки на традиционных фреймворках, и не требуется никаких дополнительных операций по управлению памятью.
Совет
Процесс monitor, встроенный в Webman, будет отслеживать использование памяти всеми процессами, и если память, используемая процессом, почти достигнет значенияmemory_limit
, установленного в php.ini, он автоматически безопасно перезапустит соответствующий процесс, чтобы освободить память, не затрагивая бизнес-процессы.
Определение утечки памяти
С увеличением количества запросов память, используемая Webman, также безгранично увеличивается (обратите внимание — безгранично увеличивается), достигая сотен мегабайт и даже больше, что и является утечкой памяти. Если память увеличивается, но после этого больше не увеличивается, это не считается утечкой памяти.
Как правило, использование десятков мегабайт памяти процессом — это нормальная ситуация, когда процесс обрабатывает очень большие запросы или поддерживает огромное количество соединений, использование памяти отдельным процессом может достигать сотен мегабайт — это тоже вполне нормально. Эта часть памяти, использованная php, возможно, не будет полностью возвращена операционной системе. Она будет оставлена для повторного использования, поэтому может возникнуть ситуация, когда после обработки какого-то большого запроса использование памяти увеличивается, но память не освобождается — это нормально. (Вызов метода gc_mem_caches() может освободить часть свободной памяти.)
Как происходит утечка памяти
Утечка памяти происходит только при выполнении следующих двух условий:
- Существуют массива с долгим сроком жизни (обратите внимание — массивы с долгим сроком жизни, обычные массивы не повлияют)
- И этот массив с долгим сроком жизни будет безгранично увеличиваться (бизнес постоянно добавляет в него данные и никогда не очищает данные)
Если оба условия 1 и 2 одновременно выполняются (обратите внимание — одновременно выполняются), то произойдет утечка памяти. В противном случае, если ни одно из условий не выполняется или выполняется только одно из условий, это не считается утечкой памяти.
Массивы с долгим сроком жизни
В Webman массивы с долгим сроком жизни включают:
- Массивы с ключевым словом static
- Свойства массивов синглтона
- Массивы с ключевым словом 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 будет периодически безопасно перезапускать процесс, в котором произошла утечка памяти, освобождая память.
Если вы действительно хотите максимально избежать утечек памяти, вы можете следовать следующим рекомендациям.
- По возможности не используйте массивы с ключевыми словами
global
иstatic
, если используете, убедитесь, что они не будут увеличиваться безгранично. - Для незнакомых классов старайтесь не использовать синглтон, инициализируйте их с помощью ключевого слова new. Если синглтон необходим, проверьте, есть ли у него массивы с безграничным увеличением.