swoole-src icon indicating copy to clipboard operation
swoole-src copied to clipboard

is small memory usage increase after each connection normal XOR sign of memory leak ?

Open yespire opened this issue 4 years ago • 6 comments

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

yespire avatar Jun 21 '21 10:06 yespire

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 avatar Jun 21 '21 13:06 NathanFreeman

@NathanFreeman

Thank you for the reply !

  1. Could you please elaborate a bit why retain a tiny memory would improve memory management ?
  2. What condition(s) would trigger swoole/php to give back the memory ? (ie: system cache pressure, php configs, etc)
  3. any way to tell swoole/php to give back the memory, ie: calling a swoole function ?

yespire avatar Jun 22 '21 09:06 yespire

  1. It spends much time on applying or releasing memory because the switch between the user mode and kernel mode.
  2. PHP will release memory for the right time. But I do not know whether php config can control it.
  3. gc_mem_caches() Reclaims memory used by the Zend Engine memory manager.

NathanFreeman avatar Jun 22 '21 14:06 NathanFreeman

try to test 10k times or more, and then use ps or top command to show the memory usage

matyhtf avatar Jun 24 '21 03:06 matyhtf

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();
	}
});

yespire avatar Jun 27 '21 02:06 yespire

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.

yespire avatar Jun 27 '21 03:06 yespire