Trying to fix memory leak due to QGraphicsScene



  • I am making a program to load a large amount of images.

    In one function I am instantiating an object

    function QtProject::load(QString path){
        QGraphicsScene* scene = new QGraphicsScene;
        scene = QPixmap(path);
       ui->qgraphicsview->setScene(scene)
    }
    

    and in function 2 I am trying to load the next set of image on keypress.

    function QtProject::next(){
        path = test[page++];
        load(path);
    }
    

    However doing so, leaves the previous image object in ram and the variable is redeclared and thus creates a memory leak. How do I solve this?



  • The thing is that in function 1 you create a "temporary" pointer to create a new GraphicsScene on the heap and then you add it on you ui's graphicsview. Which means that the only way to access your scene after the end of the function load is to use the method QGraphicsScene::scene();
    So if you load a new scene that will replace the previous one, you will loose your only reference to it, hence the memory leak.

    We need more information about your aim if you want accurate help. Yet, I can suggest that you create an array (or vector if you want a resizable container) of pointers (as you need pointers in methods like setScence(QGraphicsScene*) ) that will save a reference to the images you load so that you can still delete them if you need.



  • @Proteos said:

    a "temporary" pointer to create a new GraphicsScene on the heap and then you add it on you ui's graphicsview. Which means that the only way to access your scene after the end of the function load is to use the method QGraphicsScene::scene();

    I tried to create a pointer outside of the function for the scene object, but it instantly crashes the program



  • @Akito_Kami where exactly outside the function did you declare your pointer ?

    But it won't solve the memory leak as your pointer's value will change.



  • @Proteos The header file and then the class file



  • @Akito_Kami The problem is not in the pointer (recreating it or changing its value will cause the same issue) but in object's lifetime.

    When you create an object using the 'new' operator, your object is created on the heap and won't be destroyed until you ask for it with the instruction 'delete'.

    Which mean that the following situation will always create a memory leak :

    void function()
    {
    object* p = new object();
    }

    you will loose you pointer at the end of the function and the object will remain unaccessible in memory.

    Declaring a pointer oustide the function (as global or as member) will create a memory leak if you change it's value :

    object* p;

    void function()
    {
    p = new object();
    }

    In this case, if you call the function twice, the object created the first time will be lost in memory.

    So if you want to avoid memory leaks, you have to worry about always keeping a way to access the object you create using 'new'.
    If you need to create 30 objects using new, then you will need to store 30 pointers somewhere. Otherwise you will create memory leaks unless you use the instruction delete before changing your pointer's value.

    Was my explanation clear ? :)



  • @Proteos Making an unlimited number of pointers isn't feasible because I have no idea how many images will be loaded in the first place. Is there a way for automatic garbage collection by Qt?



  • @Akito_Kami Not knowing how many images you will load is not a problem ! You just have to use a vector (from Qt or STL as you wish) which is a kind of resizable array.
    You can declare it empty as a class member, and then add images in it with its methods push_back or insert.
    Here is the documentation of QVectors : http://doc.qt.io/qt-5/qvector.html

    Code exemple :

    in header:
    QVector<object*> yourVector;

    in class file:
    void function1()
    {
    yourVector.push_back(new object());
    }

    EDIT : the solution I'm giving actually fits a programm in which you want to keep many images in memory at the same time (for exemple if you need to reuse some them at different times). But if you only need one at a time and don't want to keep others in memory, just use the instruction delete before loading a new image.
    If you do not want to worry about the delete instruction you can use smart pointers (a lot of documentation on the Internet) whose destructors automatically delete the pointed object (provided the pointer is destructed).



  • @Proteos Quick question. if I delete something at index 0 of the vector, does it automatically shift the objects in the vector? or does push back do it for me?



  • @Akito_Kami If you use the methods QVector::remove(int index) or QVector::removeAt(int index) for any object, it will indeed readjust every indexes of the vector.

    If you remove an object at index 0, then the object at index 1 will take its place becoming object 0 and so on.

    But if your vector contains pointers, you will need to delete the object pointed (deleting does not destroy the pointer), so if you want to remove the pointer at index 0, you have to do this :

    delete yourVector.at(0); // destroys the pointed object
    yourVector.remove(0); // destroys the pointer and shift other indexes



    • Why do you instantiate more than one GraphicsScene? You can only have one scene per view. What you probably want is to instantiate and add multiple QGraphicsItem-derived objects
    • What is the line scene = path; supposed to do?


  • @Asperamanca
    What are you trying to say in your first question? I have a function which loads the path of the image into QGraphicsScene and then loads it in the QGraphicsView. I know I can only have one scene per view.
    QGraphicsItem doesn't allow me to load Pixmap objects. http://doc.qt.io/qt-5/qgraphicsitem-members.html
    Second question: Prototyping example not actual use

    Edit: I can't understand what you meant at all in your first statement



  • @Akito_Kami
    Your "load" function instantiates a new QGraphicsScene
    You call it within a loop.
    Therefore you instantiate multiple QGraphicsScenes
    I don't see where you need to do that.

    Also, I wrote "QGraphicsItem-derived", not "QGraphicsItem". If you want to show pixmaps, use QGraphicsPixmapItem, or implement your own version of QGraphicsItem to show a pixmap.

    Totally unrelated: I hate my junk mail filter. Otherwise I would have answered sooner.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.