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

QChart, do I need to delete chart series by myself? [Memory leak]



  • Do I need to delete series added to QChart by myself before the QChart is destroyed? According to this documentation, when adding series via QChart::addSeries(...), QChart takes ownership of the series, so I assumed, it would delete the series by the end of its life. But that doesn't seem to be the case, series added to the chart are leaked.

    Here is a simple example (the example doesn't use ChartView, but the same thing occurs in a full fledged application when the QChart is added to the QChartView):

    #include "vld.h"
    
    #include <QApplication>
    #include <QChart>
    #include <QStackedBarSeries>
    
    int main(int argc, char *argv[])
    {
    	{
    		QApplication a(argc, argv);
    
    		using namespace QtCharts;
    		auto chart = std::make_unique<QChart>();
    		
    		auto* const a = new QStackedBarSeries{ chart.get() };
    		auto* const b = new QStackedBarSeries{ chart.get() };
    		chart->addSeries(a);
    		chart->addSeries(b);
    
    		// manually removes and deletes the series -- fix memory leak
    		//chart->removeAllSeries();
    	}
    
    	return 0;
    }
    
    

    Visual leak detector outut can be found here.
    Running the code in a loop, increases memory usage with each iteration (notice that QChart is destroyed with each iteration).
    So, is this a bug or/and do I need to remove series added to QChart by myself before the QChart is destroyed?



  • @wdowiak
    I would have thought (never used though) that it does take ownership and so does delete itself, not you.

    Your code shows no loop, nor "notice that QChart is destroyed with each iteration", so it's hard to say without seeing.

    One thought: I don't know, but maybe you have to allow code to return to main Qt event loop to allow true deletion/release to take place (e.g. code uses deleteLater() to do the delete). Just possibly inserting a QCoreApplication::processEvents() into your loop could allow this in your test?



  • from std::make_unique docs
    "Constructs an object of type T and wraps it in a std::unique_ptr."

    I understand unique ptr is "smart" but are you sure your chart is actually getting destroyed to begin with?


  • Lifetime Qt Champion

    @wdowiak said in QChart, do I need to delete chart series by myself? [Memory leak]:

    Running the code in a loop, increases memory usage with each iteration (notice that QChart is destroyed with each iteration).

    Can you show us the code for this? Since the old series are not immediately deleted but only marked for deletion with deleteLater() they will only be cleaned once the Qt event loop is running again iirc.



  • Thank you every one for the answers.
    The series are indeed getting destroyed with a delay (tested on a normal application), but couldn't reproduce the deletion of the series in this example, I think it's because the application quits so quickly (even QCoreApplication::processEvents() didn't help). Which makes my next question, asked at the end.

    @JonB
    Yes, in the code above there is no loop, what I meant is that memory usage only increases when the same allocation code is put into a loop, e.g.:

    for (size_t i = 0; i < 100; ++i)
    {
    	{
    		auto chart = std::make_unique<QChart>();
    
    		auto* const a = new QStackedBarSeries{ chart.get() };
    		auto* const b = new QStackedBarSeries{ chart.get() };
    		chart->addSeries(a);
    		chart->addSeries(b);
    	} // chart is destroyed, series marked for deletion
    
    	QCoreApplication::processEvents(); // doesn't seem to finalize the deletion of the series
    }
    

    In normal application, the series are properly cleaned up after the loop finishes and the events are processed.
    @MrShawn
    Yes, the chart is getting destroyed. When std::unique_ptr goes out of scope, it "basically calls delete" on the object it owns.

    @Christian-Ehrlicher
    As you stated, the series are only marked for deletion, so if there is no event loop or application is about to quit, the objects marked for deletion doesn't seem to be destroyed.

    If I delete QChartView when application is still running, everything is cleaned up nicely (chart, series, etc.), but if I properly quit the application, leaving QCharView and other objects to be cleaned up by its parent, in this case - Main Window, not everything is cleaned up before the application quits, producing false-positive memory leaks (that's why I got so baffled with this, and the example in first post only enhanced that).
    For example, QChartView and QChart which is owned by the view are deleted, but chart axis and series (bar sets as well, but they are parented to the series) are only marked for deletion, and it doesn't seem to be finalized before the application quits, producing false-positive memory leaks.

    Is there a way to force deletion of every object that is marked for deletion (by deleteLater()) before the application quits (obviously only for debug purposes)?


  • Lifetime Qt Champion

    When you've a MainWindow you can overwrite the closeEvent() and delete the stuff there - but don't know if this helps here. There was also a bug report about this - at least I thought there was one but could not find it currently.



  • Deleting stuff in MainWindow's closeEvent is already too late, objects marked for deletion are not destroyed by the time applications returns from main. The only thing I have come up with (except explicitly deleting (not marking) every object in its parent destructor, which would cause different kind of problems), is to add a "clear" action to system tray (available only in debug build) that deletes central widget. This way, everything that is parented to the central widget is properly destructed by the time application is closed (easier to track memory leaks if there are no false-positives).



  • @Wdowiak Hello. How did you test on normal application that objects are destroyed (and what do you mean by "normal application")? I have got similar problem with QChartView and QChart.



  • I am confused by this thread (I am pretty new to Qt), but are we really supposed to be using smart pointers with Qt? Doesn't Qt basically come with it's "own" memory management system? It seems to me, that if my assumption is true, wouldn't this be the reason for the problem in this case (since smart ptrs are used, suddenly they own the data, not whatever mem management the Qt framework does, right?)


  • Lifetime Qt Champion

    @SimonF said in QChart, do I need to delete chart series by myself? [Memory leak]:

    Doesn't Qt basically come with it's "own" memory management system?

    Qt has parent/child relation ship (https://doc.qt.io/qt-5/objecttrees.html) and parent deletes its children when it is destroyed. But that's all. For everything else usual C++ rules apply. Shared pointers should not be used for example for everything managed by parent/child relationship (for example widgets).


Log in to reply