【问题标题】:Ratchet PHP memory leak棘轮PHP内存泄漏
【发布时间】:2014-09-22 15:32:01
【问题描述】:

我使用 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。

【问题讨论】:

  • WampServerInterface,这是否意味着您在 Windows 上?您的脚本另有说明。最好还指定您正在使用的操作系统。
  • 我不使用 Windows。我将 Linux Mint 16 与 Apache2 Web 服务器一起使用。当我说 WampServerInterface 时,我指的是 socketo.me/api/class-Ratchet.Wamp.WampServerInterface.html 我使用 WebSocket 应用程序消息传递协议 (WAMP),它包装了我的应用程序类(类名是 Socket)。我的应用程序类实现了 WampServerInterface... 我相信它与操作系统无关
  • 这是最初的设置,当我注意到这个内存问题时,我决定不使用 WAMP 并仅使用 IoServer (socketo.me/docs/server),只是为了 100% 确保即使在我建立 telnet 连接...
  • 如果你喜欢 PHP,你也可以试试 Truway(一个 PHP WAMP v2 实现)和 Crossbar.io(一个 WAMP v2 路由器):crossbar.io/docs/Getting-started-with-PHP - 这就是应用程序组件的样子github.com/crossbario/crossbar/blob/master/crossbar/crossbar/…
  • 感谢您的建议,但我宁愿继续使用 Ratchet,因为它具有 SessionProvider(与我的 symfony2 网站共享会话)等功能。

标签: php memory-leaks ratchet


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

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

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

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

    【讨论】:

    • 只有一件事,我认为 gc_collect_cycles() 应该强制 GC 释放内存...您认为放置该函数(用于测试)的最合适的位置,以便我可以看到使用 v0.3.2 和 autoDelete 对内存释放的改进?
    • onClose 处理程序是运行gc_collect_cycles()的最佳位置
    猜你喜欢
    • 1970-01-01
    • 2012-11-07
    • 2016-02-10
    • 2023-03-17
    • 2012-04-17
    • 2012-01-12
    • 2017-01-28
    • 2016-03-30
    • 1970-01-01
    相关资源
    最近更新 更多