【问题标题】:Memory leak in QSerialBus workQSerialBus 工作中的内存泄漏
【发布时间】:2017-03-15 08:35:37
【问题描述】:

大家好!

我在 Qt 5.8 上通过 QSerialBus 库实现 ModBus 时遇到问题。

问题是 - 当我尝试高速读取离散输入列表时,程序会发现内存泄漏 - 大约每秒 300-350Kb。

所以,这里是导致泄漏的函数代码:

void ModBus::queue()
{
    if(!_readList.isEmpty())
    {
        if(!checkState())
        {
            _readList.clear();
            _curPos = DiscInputPos::Full;
            queue();
            return;
        }

        QModbusDataUnit readData = QModbusDataUnit(QModbusDataUnit::DiscreteInputs, _readList.first(), 1);
        if(auto *reply = _client->sendReadRequest(readData, _serverNum))
        {
            if(!reply->isFinished())
            {
                connect(reply, &QModbusReply::errorOccurred, [=] (QModbusDevice::Error e)
                {
                    reply->deleteLater();
                    if(e == QModbusDevice::TimeoutError)
                    {
                        _readList.clear();
                        _curPos = DiscInputPos::Full;
                        stop();
                        start();
                        queue();
                    }
                });
                connect(reply, &QModbusReply::finished, this, [=]
                {
                    if(reply->error() == QModbusDevice::NoError)
                    {
                        if(reply->result().valueCount() > 0)
                        {
                            _curPos = (DiscInputPos) reply->result().value(0);
                            if(_curPos == DiscInputPos::Clear)
                                _readList.removeFirst();
                            else
                                _readList.clear();
                        }
                    }
                    else
                    {
                        _readList.clear();
                        _curPos = DiscInputPos::Full;
                    }

                    reply->deleteLater();
                    queue();
                });
            }
            else
                delete reply;
        }
        else
        {
            delete reply;
            _readList.clear();
            _curPos = DiscInputPos::Full;
            queue();
        }
    }
    else
    {
        emit sendReadResult(_curPos);
        _curPos = DiscInputPos::Full;
    }
}

_client — QModbusTcpClient

bool checkState() — 没有什么特别的,除非检查连接状态。

_readList 的最大大小为 4。

如果我用_client->sendReadRequest 注释部分代码 - 一切正常,没有任何泄漏。谁能解释一下 - 它可能是什么?

提前致谢!

【问题讨论】:

  • 也许 QApplication 的事件调度器没有太多时间来删除标记为“deleteLater”的对象(回复)?如果停止高速输入,内存会怎样?
  • 我看到几个“删除回复”,但正常路径没有。
  • @AdrianMaire,是的。我是example。即使我使用delete 而不是deleteLater() - 没有任何变化。
  • @em2er,内存不会去任何地方。
  • @em2er 时间根本不考虑它。如果您将控制权交还给事件循环,则您保证在循环将控制权交给下一个事件处理程序之前处理所有删除。如果每个事件循环都被限制在一个线程中,时间问题就没有任何意义:一次只能发生一件事,而且时间的流逝是无法衡量的,并且不会影响那些删除的行为。跨度>

标签: c++ qt memory-leaks


【解决方案1】:

我通过 0.5 秒 上的计时器解决了这个问题(导致泄漏的原因也更少),这在课堂上单次运行,检查来自ModBus 课堂的答案。仍然有泄漏,但要少得多。如果 1 秒 - 没有泄漏。

connect(d, &ModBus::sendReadResult, this, &StatusesWorker::getRead);

void StatusesWorker::getRead(DiscInputPos s)
{
        bool cleared = (s == DiscInputPos::Clear);

        if(!cleared)
            emit badSensors();
        else
            emit clearSensors();

        QTimer::singleShot(500, [=] { checkSensor(id); });
    }
}

但我认为这是不好的解决方案。

UPD。

Qt社区solved这样的问题:

connect(reply, &QModbusReply::destroyed, [this] { QTimer::singleShot(60, [this] { queue(); }); });

而且它的工作速度更快,没有泄漏。当然,checkSensor() 现在没有计时器了。

【讨论】:

  • 这不是解决方案。在内存分析器下运行它,看看究竟泄漏了什么。使用调试 Qt 构建。就目前而言,您仍然有泄漏,并且您仍然不了解泄漏的位置,因此您仍然无法确定当您更改代码中的其他内容时泄漏是否会变得更糟。
  • @KubaOber,就像 Qt 社区中所说的那样:“在循环中调用队列,不会让事件循环正常运行”。因此,请参阅 upd,我想在这种情况下这是更好的解决方案。
猜你喜欢
  • 1970-01-01
  • 2016-04-02
  • 1970-01-01
  • 2013-10-05
  • 2011-08-19
  • 2013-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多