3

我使用 Ratchet 作为一些基于浏览器的游戏的套接字服务器,我注意到一个非常奇怪的行为。

我的应用程序类实现了 WampServerInterface,我注意到在 4-5 个客户端连接和断开连接(通过 autobahn.js)之后,一些内存(大约 300KB)仍然卡住。然后,如果另外 7-8 个客户端连接和断开连接,则内存使用量不会增加。当 10-12 个新客户端连接和断开连接时,它会增加,所以我的印象是它重用了内存,但我仍然担心当许多客户端连接到服务器时它会导致内存泄漏。

然后我决定做一些测试,我做了一个实现 MessageComponentInterface 的应用程序类(这样我就可以连接到 telnet)。下面是启动服务器的代码:

<?php
ini_set('display_errors', 'On');

require 'vendor/autoload.php';
require 'bootstrap.php';

use Ratchet\Server\IoServer;
use AsterMedia\Games\Socket;

$server = IoServer::factory(
    new Socket(),
    9090,
    '127.0.0.1'
);

$server->run();

?>

我的应用程序类非常简单,看起来像这样:

    <?php

    namespace AsterMedia\Games;

    use Ratchet\MessageComponentInterface;
    use Ratchet\ConnectionInterface;

    use Symfony\Component\Console\Output\OutputInterface;

    class Socket implements MessageComponentInterface {

        public function onClose(ConnectionInterface $conn) {

            echo "Client disconnected" . $this->getMemoryUsage() . PHP_EOL;

        }

        public function onError(ConnectionInterface $conn, \Exception $e) {

            echo $e->getMessage() . PHP_EOL;
        }

        public function onOpen(ConnectionInterface $conn) {

            echo "Client connected" . $this->getMemoryUsage() . PHP_EOL;

        }

        public function onMessage(ConnectionInterface $from, $msg) {

            echo $msg . PHP_EOL;
        }

        private function getMemoryUsage() {

            return sprintf('[Memory usage (currently) %dKB/ (max) %dKB]', round(memory_get_usage(true) / 1024), memory_get_peak_usage(true) / 1024);
        }   


    }

最后,我制作了一个 bash 脚本,在无限循环中连接和断开连接:

    while true
    do
    echo "connect"
    exec 3<>/dev/tcp/127.0.0.1/9090
    exec 3<&-
    echo "disconnect"
    sleep 1
    done

运行 bash 脚本后,我注意到了相同的行为 - 几个周期后,内存使用量增加了。

这个问题是否与 Ratchet(或 React)有关,或者这只是 PHP 的问题?我忘了提到我使用启用了 GC 的 PHP 5.5.3。

4

2 回答 2

4

默认情况下,一旦主题为空,WampServer 不会释放主题。Ratchet v0.3.2 引入了一项新功能来改变这一点。Topic 对象现在有一个名为 autoDelete 的属性,如果设置为 true,一旦订阅者数量达到 0,就会销毁 Topic。

public function onSubscribe(ConnectionInterface $conn, $topic) {
    $topic->autoDelete = true;
}

保留引用的原因最初是一个(糟糕的)设计决定。实现了 autoDelete,而不是自动释放主题,因为如果用户登陆代码保持对主题的引用(假设 id 的唯一对象),该更改会导致向后兼容性中断和错误。

通过将 autoDelete 设置为 true,您最终会注意到一旦 GC 运行,您的内存消耗就会下降。

于 2014-08-09T14:49:00.860 回答
0

它是 php 流内部工作的方式。它们缓冲所有内容,一旦缓冲区增长,它不会缩小,直到脚本关闭。unset()'ing 将清除缓冲的数据,但缓冲区本身仍然存在(以防更多连接/消息出现)。它们可能会变得非常大,如果您不限制帧大小(例如,如果有人试图发送 1+ gig 文件),则可能会成为安全/稳定性问题

于 2015-11-08T15:31:18.737 回答