amphp / socket

Non-blocking socket and TLS functionality for PHP based on Amp.
https://amphp.org/socket
MIT License
235 stars 38 forks source link

Memory leak if try to write in close socket #93

Open oleg1540 opened 2 years ago

oleg1540 commented 2 years ago

Example

Loop::run(function () {
    $uri = "tcp://127.0.0.1:1337";

    Loop::repeat(500, function () {
        echo 'Counters: '. Test::$constructInc . ' - ' . Test::$destructInc . PHP_EOL;
        echo 'Memory: ' . round(memory_get_usage() / 1024, 2) . ' KB' . PHP_EOL;
    });

    $server = Amp\Socket\Server::listen($uri);

    while ($socket = yield $server->accept()) {
        $obj = new Test($socket);
        yield $obj->run();
        unset($obj);
    }
});

class Test
{
    public static int $constructInc = 0;
    public static int $destructInc = 0;

    public string $content;

    public function __construct(private \Amp\Socket\ResourceSocket $socket)
    {
        $this->content = str_repeat('a', 2048);
        self::$constructInc++;
    }

    public function __destruct()
    {
        echo 'destruct' . PHP_EOL;
        self::$destructInc++;
    }

    public function run(): \Amp\Promise
    {
        return \Amp\call(function () {
            try {
                $this->socket->close();
                yield $this->socket->write('test');
            } catch (Throwable $e) {
                echo 'catch exception' . PHP_EOL;
            }
        });
    }
}

Run script and try to connect by telnet several times

telnet 127.0.0.1 1337

Result in console

Counters: 0 - 0
Memory: 1284.35 KB
catch exception
Counters: 1 - 0
Memory: 1488.39 KB
catch exception
Counters: 2 - 0
Memory: 1522.4 KB
catch exception
Counters: 3 - 0
Memory: 1556.41 KB
catch exception
Counters: 4 - 0
Memory: 1590.41 KB
catch exception
Counters: 5 - 0
Memory: 1624.42 KB
catch exception
Counters: 6 - 0
Memory: 1658.43 KB
catch exception
Counters: 7 - 0
Memory: 1692.44 KB
catch exception
Counters: 8 - 0
Memory: 1726.45 KB
catch exception
Counters: 9 - 0
Memory: 1760.45 KB
catch exception
Counters: 10 - 0
Memory: 1794.46 KB
catch exception
Counters: 11 - 0
Memory: 1828.47 KB
catch exception
Counters: 12 - 0
Memory: 1862.48 KB

Test instances only created but not destructed. Memory consumption increases

If change vendor\amphp\byte-stream\lib\ResourceOutputStream.php:177 from

return new Failure(new ClosedException("The stream is not writable"));

to

throw new ClosedException("The stream is not writable");

got these results

Counters: 0 - 0
Memory: 1284.35 KB
catch exception
destruct
Counters: 1 - 1
Memory: 1449.94 KB
catch exception
destruct
Counters: 2 - 2
Memory: 1449.94 KB
catch exception
destruct
Counters: 3 - 3
Memory: 1449.94 KB
catch exception
destruct
Counters: 4 - 4
Memory: 1449.94 KB
catch exception
destruct
Counters: 5 - 5
Memory: 1449.94 KB
catch exception
destruct
Counters: 6 - 6
Memory: 1449.94 KB
catch exception
destruct
Counters: 7 - 7
Memory: 1449.94 KB
catch exception
destruct
Counters: 8 - 8
Memory: 1449.94 KB
catch exception
destruct
Counters: 9 - 9
Memory: 1449.94 KB
catch exception
destruct
Counters: 10 - 10
Memory: 1449.94 KB

Instances destructed, memory is stable.

PHP 8.1, amp 2.6.2, amphp/socket 1.2.0.

oleg1540 commented 2 years ago

Is it expected behavoir? )

kelunik commented 2 years ago

From a first look, this behavior doesn't look like expected behavior.

rela589n commented 6 months ago

Is it still actual for the third version?