swoole-src
swoole-src copied to clipboard
is small memory usage increase after each connection normal XOR sign of memory leak ?
Context Questions:
1. What did you do? If possible, provide a simple script for reproducing the error.
I noticed that there is a small increase in memory usage level after each connection, we can use the example code from swoole site to observe this:
<?php
use Swoole\WebSocket\Server;
use Swoole\Http\Request;
use Swoole\WebSocket\Frame;
$server = new Server("127.0.0.1", 9502);
$server->on("Start", function(Server $server)
{
echo "Swoole WebSocket Server is started at http://127.0.0.1:9502" . PHP_EOL;
});
$server->on('Open', function(Server $server, Request $request)
{
echo "connection open: {$request->fd} -- " . number_format(memory_get_usage(FALSE) / 1024, 2) . 'KB ===> ';
});
$server->on('Message', function(Server $server, Frame $frame)
{
echo "received message: {$frame->data} -- " . number_format(memory_get_usage(FALSE) / 1024, 2) . 'KB' . PHP_EOL;
});
$server->on('Close', function(Server $server, int $fd)
{
echo "close: {$fd} -- " . number_format(memory_get_usage(FALSE) / 1024, 2) . 'KB' . PHP_EOL;
});
$server->start();
2. What did you expect to see?
I would expect the memory usage of the above script to stay at or fluctuate around a fixed level.
3. What did you see instead?
The output shows steady small growth in memory usage each connection
Swoole WebSocket Server is started at http://127.0.0.1:9502
connection open: 1 -- 1,377.66KB ===> close: 1 -- 1,370.50KB
connection open: 2 -- 1,377.84KB ===> close: 2 -- 1,370.66KB
connection open: 3 -- 1,378.08KB ===> close: 3 -- 1,370.81KB
connection open: 4 -- 1,378.23KB ===> close: 4 -- 1,370.97KB
connection open: 5 -- 1,378.39KB ===> close: 5 -- 1,371.13KB
connection open: 6 -- 1,378.55KB ===> close: 6 -- 1,371.28KB
connection open: 7 -- 1,378.70KB ===> close: 7 -- 1,371.44KB
connection open: 8 -- 1,378.86KB ===> close: 8 -- 1,371.59KB
connection open: 9 -- 1,379.02KB ===> close: 9 -- 1,371.75KB
4. What version of Swoole are you using (show your php --ri swoole)?
php --ri swoole
Swoole => enabled
Author => Swoole Team <[email protected]>
Version => 4.6.7
Built => Jun 20 2021 06:18:32
coroutine => enabled with boost asm context
kqueue => enabled
rwlock => enabled
pcre => enabled
zlib => 1.2.11
brotli => E16777225/D16777225
async_redis => enabled
Directive => Local Value => Master Value
swoole.enable_coroutine => On => On
swoole.enable_library => On => On
swoole.enable_preemptive_scheduler => Off => Off
swoole.display_errors => On => On
swoole.use_shortname => On => On
swoole.unixsock_buffer_size => 262144 => 262144
5. What is your machine environment used (show your uname -a & php -v & gcc -v) ?
uname -a
Darwin loc-ye 18.7.0 Darwin Kernel Version 18.7.0: Tue Jan 12 22:04:47 PST 2021; root:xnu-4903.278.56~1/RELEASE_X86_64 x86_64
php -v
PHP 8.0.3 (cli) (built: Mar 4 2021 20:39:15) ( NTS )
Copyright (c) The PHP Group
Zend Engine v4.0.3, Copyright (c) Zend Technologies
with Zend OPcache v8.0.3, Copyright (c), by Zend Technologies
gcc -v
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/include/c++/4.2.1
Apple LLVM version 10.0.1 (clang-1001.0.46.4)
Target: x86_64-apple-darwin18.7.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
Although memory has been released , the PHP MM will cache small memory to the improvement of memory management efficiency rather than giving it back to the system.
@NathanFreeman
Thank you for the reply !
- Could you please elaborate a bit why retain a tiny memory would improve memory management ?
- What condition(s) would trigger swoole/php to give back the memory ? (ie: system cache pressure, php configs, etc)
- any way to tell swoole/php to give back the memory, ie: calling a swoole function ?
- It spends much time on applying or releasing memory because the switch between the user mode and kernel mode.
- PHP will release memory for the right time. But I do not know whether php config can control it.
- gc_mem_caches() Reclaims memory used by the Zend Engine memory manager.
try to test 10k times or more, and then use ps or top command to show the memory usage
I use 1 connection with 36k requests, it shows the following output, activity monitor / top shows roughly matching memory footprint, I also tried gc_mem_caches() idea, which produced no difference:
Swoole WebSocket Server is started at http://127.0.0.1:9502
connection open: 1 -- 1,389.93KB ===> close: 1 -- 1,384.53KB
connection open: 2 -- 1,390.12KB ===> close: 2 -- 1,384.69KB
connection open: 3 -- 1,390.27KB ===> close: 3 -- 1,384.84KB
connection open: 4 -- 1,390.43KB ===> close: 4 -- 1,385.00KB
connection open: 5 -- 1,390.59KB ===> close: 5 -- 1,385.16KB
connection open: 6 -- 1,390.74KB ===> close: 6 -- 1,385.31KB
connection open: 7 -- 1,390.90KB ===> close: 7 -- 1,385.47KB
connection open: 8 -- 1,391.05KB ===> close: 8 -- 1,385.63KB
connection open: 9 -- 1,391.21KB ===> close: 9 -- 1,385.78KB
connection open: 1500 -- 1,624.27KB ===> close: 1500 -- 1,618.75KB
connection open: 1501 -- 1,624.42KB ===> close: 1501 -- 1,618.91KB
connection open: 1502 -- 1,624.58KB ===> close: 1502 -- 1,619.06KB
connection open: 1503 -- 1,624.73KB ===> close: 1503 -- 1,619.22KB
connection open: 1504 -- 1,624.89KB ===> close: 1504 -- 1,619.38KB
connection open: 1505 -- 1,625.05KB ===> close: 1505 -- 1,619.53KB
connection open: 1506 -- 1,625.20KB ===> close: 1506 -- 1,619.69KB
connection open: 1507 -- 1,625.36KB ===> close: 1507 -- 1,619.84KB
connection open: 1508 -- 1,625.52KB ===> close: 1508 -- 1,620.00KB
connection open: 1509 -- 1,625.67KB ===> close: 1509 -- 1,620.16KB
connection open: 5000 -- 2,171.14KB ===> close: 5000 -- 2,165.63KB
connection open: 5001 -- 2,171.30KB ===> close: 5001 -- 2,165.78KB
connection open: 5002 -- 2,171.45KB ===> close: 5002 -- 2,165.94KB
connection open: 5003 -- 2,171.61KB ===> close: 5003 -- 2,166.09KB
connection open: 5004 -- 2,171.77KB ===> close: 5004 -- 2,166.25KB
connection open: 5005 -- 2,171.92KB ===> close: 5005 -- 2,166.41KB
connection open: 5006 -- 2,172.08KB ===> close: 5006 -- 2,166.56KB
connection open: 5007 -- 2,172.23KB ===> close: 5007 -- 2,166.72KB
connection open: 5008 -- 2,172.39KB ===> close: 5008 -- 2,166.88KB
connection open: 5009 -- 2,172.55KB ===> close: 5009 -- 2,167.03KB
connection open: 36001 -- 7,015.05KB ===> close: 36001 -- 7,009.54KB
connection open: 36002 -- 7,015.20KB ===> close: 36002 -- 7,009.70KB
connection open: 36003 -- 7,015.36KB ===> close: 36003 -- 7,009.85KB
connection open: 36004 -- 7,015.52KB ===> close: 36004 -- 7,010.01KB
connection open: 36005 -- 7,015.67KB ===> close: 36005 -- 7,010.16KB
connection open: 36006 -- 7,015.83KB ===> close: 36006 -- 7,010.32KB
connection open: 36007 -- 7,015.98KB ===> close: 36007 -- 7,010.48KB
connection open: 36008 -- 7,016.14KB ===> close: 36008 -- 7,010.63KB
connection open: 36009 -- 7,016.30KB ===> close: 36009 -- 7,010.79KB
A simple work around for this memory keep growing issue is to check the memory usage level at the end of the on-close callback, if going above a predefined level, call $server->reload()
$server->on('Close', function(Server $server, int $fd)
{
echo "close: {$fd} -- " . number_format(memory_get_usage(FALSE) / 1024, 2) . 'KB' . PHP_EOL;
if (memory_get_usage(FALSE) / 1024 / 1024 > 64) {
$server->reload();
}
});
Just want to clarify, the memory creeping issue seems a common theme in node and golang app, so I am not hugely concerned ~ as a periodical or condition triggered hot reloading seem mitigate the problem.
However, if there is no such issue, it would be even better.