According to this bug report it is not really a bug, but a feature in PHP7+ under the Zend Engine Memory Management:
[email protected] : This is expected behavior. On request shutdown, the Zend
memory manager does not free all allocated chunks, but rather retains
some[1] to avoid the need to reallocate them possibly for the next
request.
The suggested solution is to call: gc_mem_caches(). You can use auto_prepend_file
and auto_append_file
directives in php.ini
to execute it always if needed.
However that solution didn't help in my situation, so it is not a warranty that it will work.
As there is no easy way to change that behavior at the current moment, I found another way to solve the memory issue (it should work for PHP7,PHP8):
- Instead of using
php-cgi
, use php-fpm
- Setup FPM configuration to use the least number of children processes, but let it create children if needed, for this, you can either use
ondemand
mode or dynamic
:
/etc/php7/php-fpm.d/www.conf
:
pm = ondemand
; Adjust as needed:
pm.max_children = 10
or:
pm = dynamic
; Adjust as needed:
pm.max_children = 10
pm.start_servers = 1
pm.min_spare_servers = 1
pm.max_spare_servers = 1
The main difference between them is that ondemand
will use less memory when idle, but it will be slower when a client connects.
This is a comparison of my results:
PHP |
Mode |
Children |
Max |
Idle Mem. |
Max Mem. |
Load Time |
Max Time* |
PHP5 |
CGI |
4 |
4 |
50MB |
200MB |
5s |
15s |
PHP7 |
CGI |
4 |
4 |
200MB |
200MB |
5s |
30s |
PHP7 |
FPM / ondemand |
0 |
10 |
15MB |
500MB |
7s |
10s |
PHP7 |
FPM / dynamic |
1 |
10 |
25MB |
500MB |
6s |
10s |
- Max Load Time is tested running 50 clients simultaneously
Values in the table are approximate and only for illustration purposes (not a real benchmark in any way).