About Memory Leaks
Webman is a long-running memory framework, so we need to pay some attention to memory leaks. However, developers need not worry too much, as memory leaks occur under very extreme conditions and can be easily avoided. The development experience with Webman is essentially the same as that with traditional frameworks, and there is no need to perform extra operations for memory management.
Tip
The built-in monitor process of Webman will monitor the memory usage of all processes. If a process's memory usage is about to reach the value set bymemory_limit
in php.ini, it will automatically and safely restart the corresponding process to free up memory, with no impact on the business during this period.
Definition of Memory Leak
As requests continue to increase, the memory used by Webman will increase indefinitely (note that it is indefinitely), reaching hundreds of MB or even more; this is a memory leak. If memory usage grows but does not continue to grow afterward, it does not count as a memory leak.
It is quite normal for a process to occupy tens of MB of memory. When the process handles very large requests or maintains massive connections, it is also common for a single process to use over a hundred MB of memory. After this portion of memory is used, php may not return it all to the operating system. Instead, it will retain it for reuse, so it may appear that after handling a large request, the memory usage increases without releasing memory, which is a normal scenario. (Calling the gc_mem_caches()
method can release some free memory.)
How Memory Leaks Occur
Memory leaks must meet the following two conditions:
- There is an array with a long lifespan (note that it is a long lifespan array; a normal array is fine).
- And this long lifespan array will expand infinitely (the business keeps inserting data into it and never cleans up the data).
If both conditions 1 and 2 are satisfied at the same time (note that it is satisfied at the same time), then a memory leak will occur. Conversely, if the above conditions are not met or only one condition is satisfied, it is not a memory leak.
Long Lifespan Arrays
In Webman, long life span arrays include:
- Arrays defined with the static keyword
- Arrays as properties in singletons
- Arrays defined with the global keyword
Note
Webman allows the use of long lifespan data, but it is necessary to ensure that the data within has a limit on the number of elements and will not expand infinitely.
The following are examples explaining this.
Infinitely Expanding Static Array
class Foo
{
public static $data = [];
public function index(Request $request)
{
self::$data[] = time();
return response('hello');
}
}
The $data
array defined with the static
keyword is a long lifespan array, and in this example, the $data
array expands continuously with each request, leading to a memory leak.
Infinitely Expanding Singleton Array Property
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;
}
}
Calling Code
class Foo
{
public function index(Request $request)
{
Cache::instance()->set(time(), time());
return response('hello');
}
}
Cache::instance()
returns a Cache singleton, which is a class instance with a long lifespan; although its $data
property is not defined with the static
keyword, since the class itself has a long lifespan, the $data
is also a long lifespan array. As different key data is continuously added to the $data
array, the memory used by the program also increases, causing a memory leak.
Note
If the keys added withCache::instance()->set(key, value)
are limited in number, then there will be no memory leak, because the$data
array does not expand infinitely.
Infinitely Expanding Global Array
class Index
{
public function index(Request $request)
{
global $data;
$data[] = time();
return response($foo->sayHello());
}
}
An array defined with the global keyword will not be reclaimed after the function or class method finishes execution, so it is a long lifespan array. The code above will produce a memory leak as requests continue to increase. Similarly, an array defined with the static keyword within a function or method is also a long lifespan array; if the array expands infinitely, it will also lead to a memory leak, such as:
class Index
{
public function index(Request $request)
{
static $data = [];
$data[] = time();
return response($foo->sayHello());
}
}
Recommendations
It is recommended that developers do not pay special attention to memory leaks, as they rarely occur. If they unfortunately do occur, we can identify which code is causing the leak through pressure testing, thus locating the issue. Even if developers do not find the leak point, the built-in monitor service of Webman will safely restart the processes that experience memory leaks in a timely manner to free memory.
If you really want to avoid memory leaks as much as possible, you can refer to the following suggestions.
- Try to avoid using arrays with the
global
andstatic
keywords; if you do use them, make sure they do not expand infinitely. - For unfamiliar classes, try not to use singletons; initialize them with the new keyword. If you need a singleton, check whether it has infinitely expanding array properties.