Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

How to free RAM after using QChartView?



  • Hey,

    I'm using a simple code to draw a chart, here an example - just the values of the QLineSeries are faked:

    QLineSeries *series = new QLineSeries();
    
    series->append(0, 1);
    series->append(1, 2);
    series->append(2, 5);
    series->append(3, 3);
    
    QChart *chart = new QChart();
    chart->legend()->hide();
    chart->addSeries(series);
    chart->createDefaultAxes();
    
    QChartView *chartView = new QChartView(chart);
    chartView->setRenderHint(QPainter::Antialiasing);
    chartView->resize(800, 600);
    chartView->show();
    

    I now have the problem that I use more RAM with every call. What's the correct way to handle it?
    I tried to save the pointer of the Chart, ChartView and LineSeries and constantly checking if the window is still open/active. If the window is closed, I tried to use the deleteLater function but this crashs my application.

    Can someone help please? Thanks


  • Lifetime Qt Champion

    @HTWAMD said in How to free RAM after using QChartView?:

    What's the correct way to handle it?

    You're creating objects without deleting them - so delete them and the memory will be freed - C++ basics.



  • Well yes, sure. But like I said using the delete or deleteLater function isn't working. It crashes the whole application.

    chartView->deleteLater();
    chart->deleteLater();
    //Or
    delete chartView;
    delete chart; 
    
    

    I tried these function after the window of the chart is closed but no success.


  • Lifetime Qt Champion

    @HTWAMD said in How to free RAM after using QChartView?:

    It crashes the whole application.

    Because you delete it twice:

    https://doc.qt.io/qt-5/qchartview.html#QChartView-1 : The ownership of the chart is passed to the chart view.

    And please provide a minimal example where it crashes - you code above doesn't show where/how you delete the objects.



  • I tried some more stuff but I' cant deal with the Chart stuff :(

    Here is - basically - my code I use (header + source, the ui contains just a widget and two spinboxes):

    namespace Ui {
    class EventDrawer;
    }
    
    class EventDrawer : public QWidget
    {
        Q_OBJECT
    
    public:
        explicit EventDrawer(QWidget *parent, QTableWidget* listEvents);
        ~EventDrawer();
        void draw_chart();
    
    public slots:
        void closeEvent (QCloseEvent *event);
    
    private slots:
        void on_spinBox_min_valueChanged(int arg1);
        void on_spinBox_max_valueChanged(int arg1);
    
    private:
        Ui::EventDrawer *ui;
    
        QChart* Chart;
        QChartView* chartView;
        QVBoxLayout* LayoutChart;
        QLineSeries* series;
        QTableWidget* table_ptr;
    
        bool init;
        int min_value;
        int max_value;
    };
    
    #endif // EVENTDRAWER_H
    
    
    
    
    #include "eventdrawer.h"
    #include "ui_eventdrawer.h"
    
    EventDrawer::EventDrawer(QWidget *parent, QTableWidget* listEvents) :
        ui(new Ui::EventDrawer)
    {
        ui->setupUi(this);
        this->setStyleSheet(parent->styleSheet());
    
        init = true;
        min_value = 0;
        max_value = 0;
    
        table_ptr = listEvents;
        draw_chart();
        init = false;
    }
    
    EventDrawer::~EventDrawer()
    {
        delete ui;
    }
    
    void EventDrawer::closeEvent (QCloseEvent *event)
    {
        delete ui->widget->layout();
    
        event->accept();
    }
    
    void EventDrawer::draw_chart()
    {
        int counter = 1;
        QMap<QString, int> InfoTypes;
        for (int i=0; i < table_ptr->rowCount(); i++)
        {
            int value = i;
            QString info_type = table_ptr->item(value, 1)->text();
            if (InfoTypes[info_type] == 0)
                InfoTypes[info_type] = counter++;
        }
    
        int event_type_count = InfoTypes.count();
        if (event_type_count == 0)
            return;
    
    
        int min = 9999999;
        int max = -9999999;
    
        series = new QLineSeries[event_type_count];
        for (int i=0; i < table_ptr->rowCount(); i++)
        {
            int value = i;
            if (ui->checkBox_oldFirst->isChecked())
                value = (table_ptr->rowCount()-1) - i;
    
            QString info_type = table_ptr->item(value, 1)->text();
            float info_value = table_ptr->item(value, 2)->text().toFloat();
    
            if (info_value < min)
                min = info_value;
            if (info_value > max)
                max = info_value;
    
            if (ui->checkBox_dateAxis->isChecked())
            {
                QDateTime timestamp = QDateTime::fromString(table_ptr->item(value, 3)->text(), "yyyy-MM-dd hh:mm:ss.zzz");
                series[InfoTypes[info_type]-1].append(timestamp.toMSecsSinceEpoch(), info_value);
            }
            else
            {
                series[InfoTypes[info_type]-1].append(i, info_value);
            }
            series[InfoTypes[info_type]-1].setName(info_type);
        }
    
        Chart = new QChart();
        for (int i=0; i < event_type_count; i++)
            Chart->addSeries(&series[i]);
    
        if (ui->checkBox_dateAxis->isChecked())
        {
            QDateTimeAxis *axisX = new QDateTimeAxis;
            axisX->setTickCount(14);
            axisX->setFormat("MM.dd hh:mm:ss");
            axisX->setTitleText("Date");
            Chart->addAxis(axisX, Qt::AlignBottom);
            series->attachAxis(axisX);
            Chart->axisX()->setTitleText("Date");
    
            QValueAxis *axisY = new QValueAxis;
            axisY->setLabelFormat("%i");
            Chart->addAxis(axisY, Qt::AlignLeft);
            series->attachAxis(axisY);
        }
        else
        {
            Chart->createDefaultAxes();
            Chart->axisX()->setRange(0, table_ptr->rowCount());
        }
    
        if (min_value != 0 || max_value != 0)
        {
            Chart->axisY()->setRange(min_value, max_value);
        }
        else
        {
            ui->spinBox_max->setValue(max);
            ui->spinBox_min->setValue(min);
        }
    
        chartView = new QChartView(Chart);
        chartView->setRenderHint(QPainter::Antialiasing);
    
        LayoutChart = new QVBoxLayout();
        LayoutChart->addWidget(chartView);
        ui->widget->setLayout(LayoutChart);
    }
    
    void EventDrawer::on_spinBox_min_valueChanged(int arg1)
    {
        if (init)
            return;
    
        min_value = arg1;
        Chart->axisY()->setRange(min_value, max_value);
    }
    
    void EventDrawer::on_spinBox_max_valueChanged(int arg1)
    {
        if (init)
            return;
    
        max_value = arg1;
        Chart->axisY()->setRange(min_value, max_value);
    }
    

    What I would like to do now, is to delete / free the ram when the window is closed. So if the closeEvent function is called, delete the chartView, Chart, Series.
    Could someone please show me how to do this?


  • Lifetime Qt Champion

    Again: please provide a minimal, compilable example if you think there is a crash and / or a memleak. Delete your chartView in the dtor and the memory will be freed afaics.



  • Okay I made a very short, compilable example, here is the download link:
    https://filetransfer.io/data-package/wck4NloP

    Compile, run the application, click draw chart, close the window, crash.
    Can you or anyone please tell me how to modify the code / the dtor to avoid the crash?


  • Lifetime Qt Champion

    First in the dtor only 'delete ui' is needed - the rest is deleted due to parent child relationships.

    Second please take a look at

    QLineSeries *series = new QLineSeries[event_type_count];
    ...
    Chart->addSeries(&series[i]);
    

    since addSeries() is taking ownership, it's later also calling 'delete &series[i]' - this can't work.

    Use a QVector<QLineSeries*>, no need to hold it as member (at least not in your testcase).



  • Thanks a lot.
    dtor is now delete ui only and the QLineSeries using a QVector, now it's working perfectly :)


  • Lifetime Qt Champion

    @HTWAMD Then please mark this topic as solved, thx.


Log in to reply