Утечка памяти QT6

#c #qt #memory-leaks

Вопрос:

У меня есть два окна, одно с настройками и не запускается при запуске, а другое, которое обновляет информацию каждую минуту. Но в течение некоторого времени я обнаружил, что использование памяти в диспетчере задач медленно увеличивается.

Я устанавливаю Deleaker для отслеживания утечки памяти, но она отображается только в библиотеках QT (QT6Guid.dll и т.д.).

Фрагмент кода обновленного окна, который отображается при запуске:

 TaskTrackerScreen::TaskTrackerScreen(Controller *controller, QWidget *parent) :
    Screen(controller, parent),
    ui(new Ui::TaskTrackerScreen),
    m_controller(controller) {

    ui->setupUi(this);

    m_size = QSize(1200, 900);
    m_titleBarHeight = 30;
    m_exitButtonWidth = 55;
    m_iconExitScale = 0.34f;

    m_controller->getTasks();

    this->drawTitleBar(this, "SG Task Tracker");
    this->drawContent();

    m_controller->startActivityScan();
}

TaskTrackerScreen::~TaskTrackerScreen() {
    m_controller->stopActivityScan();
    delete ui;
    delete m_tasksWidgetsContainer;
    delete m_playIcon;
    delete m_pauseIcon;
    delete m_taskListWidget;
    delete m_activeTaskWidget;
}

void TaskTrackerScreen::drawContent() {
    m_content = Screen::drawContent(this);

    m_playIcon = m_pixmapFactory->createElement(":/Icons/play.png", QSize(40, 40));
    m_pauseIcon = m_pixmapFactory->createElement(":/Icons/pause.png", QSize(40, 40));

    m_activeTaskWidget = m_widgetFactory->createElement(m_content);
    m_widgetFactory->applyStyle(m_activeTaskWidget,
                                QRect(20, 0, 1160, 100),
                                "border-bottom-left-radius:15px;border-bottom-right-radius:15px;border:2px solid rgb(75,75,75);border-top:0px solid transparent;");
    m_activeTaskWidget->setLayout(drawActiveTaskWidget());

    m_taskListWidget = m_widgetFactory->createElement();
    m_tasksWidgetsContainer = new QVBoxLayout;
    m_tasksWidgetsContainer->setContentsMargins(0, 0, 0, 0);
    m_tasksWidgetsContainer->setSpacing(5);

    drawTasksList();

    m_taskListWidget->setLayout(m_tasksWidgetsContainer);

    auto scrollArea = m_scrollAreaFactory->createElement(m_content);
    m_scrollAreaFactory->applyStyle(scrollArea, QRect(10, 120, 1190, 750));
    scrollArea->setWidget(m_taskListWidget);
}

QHBoxLayout* TaskTrackerScreen::drawActiveTaskWidget() {
    auto activeTask = m_controller->activeTask();
    m_font->setPixelSize(19);
    auto layout = new QHBoxLayout();
    layout->setContentsMargins(10, 11, 10, 11);
    layout->setSpacing(0);

    auto indexPushButton = m_pushButtonFactory->createElement();
    m_pushButtonFactory->applyStyle(indexPushButton,
                                    QSize(80, 78),
                                    (activeTask != Q_NULLPTR ? activeTask->idReadable() : ""),
                                    m_font,
                                    Q_NULLPTR,
                                    "QPushButton{border:2px solid rgb(75,75,75);}QPushButton:hover{border:2px solid rgb(75,75,75);background-color:rgb(30,30,30);}");
    layout->addWidget(indexPushButton, Qt::AlignLeft);

    if (m_controller->activeTask() != Q_NULLPTR) {
        indexPushButton->setCursor(Qt::PointingHandCursor);
    }
    connect(indexPushButton, SIGNAL(clicked()), this, SLOT(openIssueLink()));

    auto summaryLabel = m_labelFactory->createElement();
    m_labelFactory->applyStyle(summaryLabel,
                               m_font,
                               (activeTask != Q_NULLPTR ? activeTask->summary() : ""),
                               "margin:0px;padding-bottom:2px;border:2px solid rgb(75,75,75);border-radius:0px;border-bottom:0px solid transparent;");
    summaryLabel->setAlignment(Qt::AlignLeft);
    summaryLabel->setFixedSize(505, 31);

    m_font->setPixelSize(12);
    auto descriptionLabel = m_labelFactory->createElement();
    m_labelFactory->applyStyle(descriptionLabel,
                               m_font,
                               (activeTask != Q_NULLPTR ? activeTask->description() : ""),
                               "margin:0px;padding:8px;border:2px solid rgb(75,75,75);border-top:0px solid transparent;");
    descriptionLabel->setWordWrap(true);
    descriptionLabel->setAlignment(Qt::AlignLeft);
    descriptionLabel->setFixedSize(505, 46);

    auto infoLayout = new QVBoxLayout;
    infoLayout->setContentsMargins(0, 0, 0, 0);
    infoLayout->setSpacing(0);
    infoLayout->addWidget(summaryLabel, Qt::AlignLeft);
    infoLayout->addWidget(descriptionLabel, Qt::AlignLeft);

    layout->addLayout(infoLayout, Qt::AlignLeft);

    m_font->setPixelSize(19);
    auto priorityLabel = m_labelFactory->createElement();
    m_labelFactory->applyStyle(priorityLabel,
                               m_font,
                               (activeTask != Q_NULLPTR ? activeTask->priority() : ""),
                               (QString) "margin:0px;border:2px solid rgb(75,75,75);border-radius:0px;");
    priorityLabel->setAlignment(Qt::AlignLeft | Qt::AlignBottom);
    priorityLabel->setFixedSize(200, 38);

    auto stateLabel = m_labelFactory->createElement();
    m_labelFactory->applyStyle(stateLabel,
                               m_font,
                               (activeTask != Q_NULLPTR ? activeTask->state() : ""),
                               "margin:0px;border:2px solid rgb(75,75,75);border-bottom-right-radius:0px;");
    stateLabel->setAlignment(Qt::AlignLeft | Qt::AlignBottom);
    stateLabel->setFixedSize(200, 38);

    auto detailsLayout = new QVBoxLayout;
    detailsLayout->setContentsMargins(0, 0, 0, 0);
    detailsLayout->setSpacing(0);
    detailsLayout->addWidget(priorityLabel, Qt::AlignLeft);
    detailsLayout->addWidget(stateLabel, Qt::AlignLeft);

    layout->addLayout(detailsLayout, Qt::AlignLeft);

    auto dueDateLabel = m_labelFactory->createElement();
    m_labelFactory->applyStyle(dueDateLabel,
                               m_font,
                               (activeTask != Q_NULLPTR ? "Срок: "   QLocale{QLocale::Russian}.toString(activeTask->dueDate(), "dd-MM-yyyy") : "Срок: "),
                               (QString) "margin:0px;border:2px solid rgb(75,75,75);border-radius:0px;");
    dueDateLabel->setAlignment(Qt::AlignLeft | Qt::AlignBottom);
    dueDateLabel->setFixedSize(280, 38);

    auto spentTimeLabel = m_labelFactory->createElement();
    m_labelFactory->applyStyle(spentTimeLabel,
                               m_font,
                               (activeTask != Q_NULLPTR ? "Затраченно: "   activeTask->spentTime().toString() : "Затраченно: "),
                               "margin:0px;border:2px solid rgb(75,75,75);border-bottom-left-radius:0px;");
    spentTimeLabel->setAlignment(Qt::AlignLeft | Qt::AlignBottom);
    spentTimeLabel->setFixedSize(280, 38);

    auto timeLayout = new QVBoxLayout;
    timeLayout->setContentsMargins(0, 0, 0, 0);
    timeLayout->setSpacing(0);
    timeLayout->addWidget(dueDateLabel, Qt::AlignLeft);
    timeLayout->addWidget(spentTimeLabel, Qt::AlignLeft);

    layout->addLayout(timeLayout, Qt::AlignLeft);

    auto playPauseButton = m_pushButtonFactory->createElement();

    if (activeTask != Q_NULLPTR amp;amp; m_controller->isRunning()) {
        m_pushButtonFactory->applyStyle(playPauseButton,
                                        QSize(70, 78),
                                        Q_NULLPTR,
                                        Q_NULLPTR,
                                        m_pauseIcon,
                                        "QPushButton{border:2px solid rgb(75,75,75);}QPushButton:hover{border:2px solid rgb(75,75,75);}");
    } else {
        m_pushButtonFactory->applyStyle(playPauseButton,
                                        QSize(70, 78),
                                        Q_NULLPTR,
                                        Q_NULLPTR,
                                        m_playIcon,
                                        "QPushButton{border:2px solid rgb(75,75,75);}QPushButton:hover{border:2px solid rgb(75,75,75);}");
    }

    playPauseButton->setIconSize(QSize(40, 40));

    if (activeTask == Q_NULLPTR) {
        playPauseButton->setEnabled(false);
    }

    layout->addWidget(playPauseButton, Qt::AlignRight);

    connect(playPauseButton, amp;QPushButton::released, m_controller,
            [=]() {
        auto activeTask = m_controller->activeTask();

        if (activeTask != Q_NULLPTR amp;amp; m_controller->isRunning()) {
            m_controller->stopTimeTrack();
            m_pushButtonFactory->applyStyle(playPauseButton,
                                            QSize(70, 78),
                                            Q_NULLPTR,
                                            Q_NULLPTR,
                                            m_playIcon,
                                            "QPushButton{border:2px solid rgb(75,75,75);}QPushButton:hover{border:2px solid rgb(75,75,75);}");

            m_pushButtonFactory->applyStyle((QPushButton*) activeTask
                                                                    ->widgetSlot()
                                                                    ->layout()
                                                                    ->itemAt(4)
                                                                    ->widget(),
                                            QSize(70, 78),
                                            Q_NULLPTR,
                                            Q_NULLPTR,
                                            m_playIcon,
                                            "QPushButton{border:2px solid rgb(75,75,75);}QPushButton:hover{border:2px solid rgb(75,75,75);}");
        } else {
            m_controller->startTimeTrack(activeTask);
            m_pushButtonFactory->applyStyle(playPauseButton,
                                            QSize(70, 78),
                                            Q_NULLPTR,
                                            Q_NULLPTR,
                                            m_pauseIcon,
                                            "QPushButton{border:2px solid rgb(75,75,75);}QPushButton:hover{border:2px solid rgb(75,75,75);}");

            if (activeTask != Q_NULLPTR) {
                m_pushButtonFactory->applyStyle((QPushButton*) activeTask
                                                                        ->widgetSlot()
                                                                        ->layout()
                                                                        ->itemAt(4)
                                                                        ->widget(),
                                                QSize(70, 78),
                                                Q_NULLPTR,
                                                Q_NULLPTR,
                                                m_pauseIcon,
                                                "QPushButton{border:2px solid rgb(75,75,75);}QPushButton:hover{border:2px solid rgb(75,75,75);}");
            }
        }
    });

    return layout;
}

void TaskTrackerScreen::openIssueLink() {
    auto activeTask = m_controller->activeTask();
    if (activeTask != Q_NULLPTR) {
        QDesktopServices::openUrl(QUrl(ConfigManager::config.baseUrl   "/issue/"   activeTask->idReadable()   "/", QUrl::TolerantMode));
    }
}

void TaskTrackerScreen::drawTasksList() {
    while (m_tasksWidgetsContainer->itemAt(0) != Q_NULLPTR) {
        auto taskWidget = m_tasksWidgetsContainer->itemAt(0)->widget();
        m_tasksWidgetsContainer->removeWidget(taskWidget);
        delete taskWidget;
    }

    auto tasks = m_controller->tasks();
    m_widgetFactory->applyStyle(m_taskListWidget, QRect(0, 0, 1180, tasks.size() * 85));

    auto index = 0;
    for (auto task : tasks) {
        m_tasksWidgetsContainer->addWidget(drawTaskWidget(task, index, 80));
        index  ;
    }
}

QWidget* TaskTrackerScreen::drawTaskWidget(Task *task, int id, int height) {
    m_font->setPixelSize(19);
    auto widget = m_widgetFactory->createElement();
    m_widgetFactory->applyStyle(widget,
                                QRect(0, 0, 1175, height),
                                "border:2px solid rgb(75,75,75);");

    auto layout = new QHBoxLayout(widget);
    layout->setContentsMargins(2, 2, 2, 2);
    layout->setSpacing(0);

    auto indexLabel = m_labelFactory->createElement();
    m_labelFactory->applyStyle(indexLabel,
                               m_font,
                               QString::number(id   1),
                               "margin:0px;border-right:2px solid rgb(75,75,75);");
    layout->addWidget(indexLabel, Qt::AlignLeft);
    indexLabel->setFixedWidth(80);

    auto summaryLabel = m_labelFactory->createElement();
    m_labelFactory->applyStyle(summaryLabel,
                               m_font,
                               task->summary(),
                               "margin:0px;margin-left:-2px;");
    summaryLabel->setAlignment(Qt::AlignLeft);
    summaryLabel->setFixedSize(545, qRound((height - 4) * 0.4));

    m_font->setPixelSize(12);
    auto descriptionLabel = m_labelFactory->createElement();
    m_labelFactory->applyStyle(descriptionLabel,
                               m_font,
                               task->description(),
                               "margin:0px;margin-top:-5px;");
    descriptionLabel->setWordWrap(true);
    descriptionLabel->setAlignment(Qt::AlignLeft);
    descriptionLabel->setFixedSize(545, qRound((height - 4) * 0.6));

    auto infoLayout = new QVBoxLayout;
    infoLayout->setContentsMargins(0, 0, 0, 0);
    infoLayout->setSpacing(0);
    infoLayout->addWidget(summaryLabel, Qt::AlignLeft);
    infoLayout->addWidget(descriptionLabel, Qt::AlignLeft);

    layout->addLayout(infoLayout, Qt::AlignLeft);

    m_font->setPixelSize(19);
    auto priorityLabel = m_labelFactory->createElement();
    m_labelFactory->applyStyle(priorityLabel,
                               m_font,
                               task->priority(),
                               (QString) "margin:0px;border:2px solid rgb(75,75,75);border-top:0px solid transparent;"
                                 (QString) (task->priority() == SGTT::Priority_Ru[4] ? "color:rgb(255,179,25);" : ""));
    priorityLabel->setAlignment(Qt::AlignLeft | Qt::AlignBottom);
    priorityLabel->setFixedSize(200, qRound((height - 4) * 0.5));

    auto stateLabel = m_labelFactory->createElement();
    m_labelFactory->applyStyle(stateLabel,
                               m_font,
                               task->state(),
                               "margin:0px;border:2px solid rgb(75,75,75);border-bottom:0px solid transparent;");
    stateLabel->setAlignment(Qt::AlignLeft | Qt::AlignBottom);
    stateLabel->setFixedSize(200, qRound((height - 4) * 0.5));

    auto detailsLayout = new QVBoxLayout;
    detailsLayout->setContentsMargins(0, 0, 0, 0);
    detailsLayout->setSpacing(0);
    detailsLayout->addWidget(priorityLabel, Qt::AlignLeft);
    detailsLayout->addWidget(stateLabel, Qt::AlignLeft);

    layout->addLayout(detailsLayout, Qt::AlignLeft);

    auto dueDateLabel = m_labelFactory->createElement();
    m_labelFactory->applyStyle(dueDateLabel,
                               m_font,
                               "Срок: "   QLocale{QLocale::Russian}.toString(task->dueDate(), "dd-MM-yyyy"),
                               (QString) "margin:0px;border:2px solid rgb(75,75,75);border-top:0px solid transparent;"
                                 (QString) (QDate::currentDate() >= task->dueDate() ? "color:rgb(255,179,25);" : ""));
    dueDateLabel->setAlignment(Qt::AlignLeft | Qt::AlignBottom);
    dueDateLabel->setFixedSize(280, qRound((height - 4) * 0.5));

    auto spentTimeLabel = m_labelFactory->createElement();
    m_labelFactory->applyStyle(spentTimeLabel,
                               m_font,
                               "Затраченно: "   task->spentTime().toString(),
                               "margin:0px;border:2px solid rgb(75,75,75);border-bottom:0px solid transparent;");
    spentTimeLabel->setAlignment(Qt::AlignLeft | Qt::AlignBottom);
    spentTimeLabel->setFixedSize(280, qRound((height - 4) * 0.5));

    auto timeLayout = new QVBoxLayout;
    timeLayout->setContentsMargins(0, 0, 0, 0);
    timeLayout->setSpacing(0);
    timeLayout->addWidget(dueDateLabel, Qt::AlignLeft);
    timeLayout->addWidget(spentTimeLabel, Qt::AlignLeft);

    layout->addLayout(timeLayout, Qt::AlignLeft);

    auto playPauseButton = m_pushButtonFactory->createElement();

    auto activeTask = m_controller->activeTask();

    if (activeTask != Q_NULLPTR amp;amp; m_controller->isRunning() amp;amp; activeTask->idReadable() == task->idReadable()) {
        m_pushButtonFactory->applyStyle(playPauseButton,
                                            QSize(70, (height - 4)),
                                            Q_NULLPTR,
                                            Q_NULLPTR,
                                            m_pauseIcon);
    } else {
        m_pushButtonFactory->applyStyle(playPauseButton,
                                            QSize(70, (height - 4)),
                                            Q_NULLPTR,
                                            Q_NULLPTR,
                                            m_playIcon);
    }

    playPauseButton->setIconSize(QSize(40, 40));
    layout->addWidget(playPauseButton, Qt::AlignRight);

    task->setWidgetSlot(widget);

    connect(playPauseButton, amp;QPushButton::released, m_controller,
            [=]() {
        auto activeTask = m_controller->activeTask();

        if (activeTask != Q_NULLPTR amp;amp; m_controller->isRunning() amp;amp; activeTask->idReadable() == task->idReadable()) {
            m_controller->stopTimeTrack();
            m_pushButtonFactory->applyStyle(playPauseButton,
                                                QSize(70, 76),
                                                Q_NULLPTR,
                                                Q_NULLPTR,
                                                m_playIcon);
        } else {
            if (activeTask != Q_NULLPTR amp;amp; m_controller->isRunning()) {
                m_pushButtonFactory->applyStyle((QPushButton*) activeTask
                                                                    ->widgetSlot()
                                                                    ->layout()
                                                                    ->itemAt(4)
                                                                    ->widget(),
                                                QSize(70, 76),
                                                Q_NULLPTR,
                                                Q_NULLPTR,
                                                m_playIcon);
            }

            m_controller->startTimeTrack(task);
            m_pushButtonFactory->applyStyle(playPauseButton,
                                                QSize(70, 76),
                                                Q_NULLPTR,
                                                Q_NULLPTR,
                                                m_pauseIcon);
        }

        redrawActiveWidgetLayout();
    });

    return widget;
}

void TaskTrackerScreen::redrawActiveWidgetLayout() {
    delete m_activeTaskWidget->layout();
    m_activeTaskWidget->setLayout(drawActiveTaskWidget());
}

void TaskTrackerScreen::redrawSpentTimeWidgets() {
    auto activeTask = m_controller->activeTask();
    auto widget = activeTask->widgetSlot();

    auto spentTimeLabel = (QLabel*) widget
                          ->layout()
                          ->itemAt(3)
                          ->layout()
                          ->itemAt(1)
                          ->widget();

    spentTimeLabel->setText("Затраченно: "   activeTask->spentTime().toString());

    spentTimeLabel = (QLabel*) m_activeTaskWidget
                     ->layout()
                     ->itemAt(3)
                     ->layout()
                     ->itemAt(1)
                     ->widget();

    spentTimeLabel->setText("Затраченно: "   activeTask->spentTime().toString());
}
 

Заводы по производству элементов:

 QPixmap *QPixmapFactory::createElement(QWidget *parent) {
    parent = Q_NULLPTR;
    return new QPixmap;
}

QPixmap *QPixmapFactory::createElement(QString fileName, QSize size) {
    auto newElement = new QPixmap(fileName);
    auto element = newElement->scaled(size, Qt::KeepAspectRatio);
    delete newElement;
    return new QPixmap(element);
}

QPixmap* QPixmapFactory::changeColor(QPixmap *element, QColor maskColor, QColor objectColor) {
    auto newElement = new QPixmap(element->size());
    newElement->fill(objectColor);
    newElement->setMask(element->createMaskFromColor(maskColor));
    delete element;
    return newElement;
}

QPixmap* QPixmapFactory::changeScale(QPixmap *element, float scale) {
    auto newElement = element->scaled(element->size() * scale, Qt::KeepAspectRatio);
    delete element;
    return new QPixmap(newElement);
}

inline QWidget* createElement(QWidget *parent = Q_NULLPTR) override { return new QWidget(parent); }

void QWidgetFactory::applyStyle(QWidget *element, QRect geometry, QString additionalStyleSheet) {
    auto styleSheet = (QString) "background-color:rgb(25,25,25);";

    element->setMinimumSize(geometry.width(), geometry.height());
    element->setMaximumSize(geometry.width(), geometry.height());
    element->setGeometry(geometry);

    if (additionalStyleSheet != Q_NULLPTR) {
        styleSheet.append(additionalStyleSheet);
    }

    element->setStyleSheet(styleSheet);
}

inline QScrollArea* createElement(QWidget *parent = Q_NULLPTR) override { return new QScrollArea(parent); }

void QScrollAreaFactory::applyStyle(QScrollArea *element, QRect geometry, QString additionalStyleSheet) {
    auto styleSheet = (QString) "QScrollBar:vertical {"
                                "    border: 1px solid rgb(25,25,25);"
                                "    background:rgb(25,25,25);"
                                "    width:10px;    "
                                "    margin: 0px 0px 0px 0px;"
                                "}"
                                "QScrollBar::handle:vertical {"
                                "    background: rgb(25,25,25);"
                                "    min-height: 0px;"
                                "}"
                                "QScrollBar::add-line:vertical {"
                                "    background: rgb(25,25,25);"
                                "    height: 0px;"
                                "    subcontrol-position: bottom;"
                                "    subcontrol-origin: margin;"
                                "}"
                                "QScrollBar::sub-line:vertical {"
                                "    background: rgb(25,25,25);"
                                "    height: 0 px;"
                                "    subcontrol-position: top;"
                                "    subcontrol-origin: margin;"
                                "}";

    element->setGeometry(geometry);

    if (additionalStyleSheet != Q_NULLPTR) {
        styleSheet.append(additionalStyleSheet);
    }

    element->verticalScrollBar()->setStyleSheet(styleSheet);
    element->horizontalScrollBar()->setStyleSheet("width: 0px;");
    element->setStyleSheet("border:0px solid transparent;");
}

inline QPushButton* createElement(QWidget *parent = Q_NULLPTR) override { return new QPushButton(parent); }


void QPushButtonFactory::applyStyle(QPushButton *element,
                                    QSize size,
                                    QString text,
                                    QFont *font,
                                    QPixmap *icon,
                                    QString additionalStyleSheet) {
    auto styleSheet = (QString) "QPushButton{border:1px solid rgb(75,75,75);background-color:rgb(30,30,30);color:rgb(240,240,240);}QPushButton:hover{background-color:rgb(60,60,60);color:rgb(240,240,240);}";

    if (text != Q_NULLPTR) {
        element->setText(text);
    }

    if (font != Q_NULLPTR) {
        font->setPointSize(16);
        element->setFont(*font);
    }

    if (icon != Q_NULLPTR) {
        element->setIcon(*icon);
    }

    if (additionalStyleSheet != Q_NULLPTR) {
        styleSheet.append(additionalStyleSheet);
    }

    element->setStyleSheet(styleSheet);
    if (size.height() != 0) {
        element->setFixedSize(size);
    }
}

inline QLabel* createElement(QWidget *parent = Q_NULLPTR) override { return new QLabel(parent); }


void QLabelFactory::applyStyle(QLabel *element, QFont *font, QString text, QString additionalStyleSheet) {
    auto styleSheet = (QString) "padding:5px;margin:5px;color:rgb(240,240,240);border:0px solid white;";

    element->setText(text);
    element->setFont(*font);

    if (additionalStyleSheet != Q_NULLPTR) {
        styleSheet.append(additionalStyleSheet);
    }

    element->setStyleSheet(styleSheet);
    element->setAlignment(Qt::AlignCenter);
}

 

А вот xml-файл результатов удаления: https://dropmefiles.com/OoyMb]

Я не понимаю, почему stacktrace показывает проблему с QLineEdit, если в виджете нет этого элемента…

Комментарии:

1. Вы пробовали сделать два снимка, а затем понять разницу? Это должно помочь пересмотреть только «совокупные» ассигнования? Есть ли шансы поделиться файлом моментального снимка (*.dsnapshot)?

2. @ArtemRazin вот два реальных снимка dropmefiles.com/irJMy Извините за поздний ответ