Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Memory leak in QGraphcisPixmapItem.setPixmap()?
Forum Updated to NodeBB v4.3 + New Features

Memory leak in QGraphcisPixmapItem.setPixmap()?

Scheduled Pinned Locked Moved Unsolved General and Desktop
11 Posts 3 Posters 3.1k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • N Offline
    N Offline
    nckma
    wrote on last edited by
    #1

    hello
    I met strange issue.
    I have application which uses QGraphcsiView, QGraphcisScene and QGraphicsPixmapItem on scene.
    My GraphcsiVew has assigned OpenGL as

    gl = new QGLWidget();
    setViewport(gl);
    

    Periodically Pixmap item gets updated with new image.

    Only on some computers with some OSes I get memory leak on call to setPixmap().
    For example IN windows 10 my app is OK.
    On windows 8.1 my app generates huge memory leaks and crashes.

    This somehow is dependant to OpenGL. If I remove setViewPort(gl); then all is OK in both OSes.
    My app is big and complex so of cause reason can be anywhere.

    I made a simple test. I just little modified QT example "moveblocks"

    /****************************************************************************
    **
    ** Copyright (C) 2015 The Qt Company Ltd.
    ** Contact: http://www.qt.io/licensing/
    **
    ** This file is part of the QtCore module of the Qt Toolkit.
    **
    ** $QT_BEGIN_LICENSE:BSD$
    ** You may use this file under the terms of the BSD license as follows:
    **
    ** "Redistribution and use in source and binary forms, with or without
    ** modification, are permitted provided that the following conditions are
    ** met:
    **   * Redistributions of source code must retain the above copyright
    **     notice, this list of conditions and the following disclaimer.
    **   * Redistributions in binary form must reproduce the above copyright
    **     notice, this list of conditions and the following disclaimer in
    **     the documentation and/or other materials provided with the
    **     distribution.
    **   * Neither the name of The Qt Company Ltd nor the names of its
    **     contributors may be used to endorse or promote products derived
    **     from this software without specific prior written permission.
    **
    **
    ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
    **
    ** $QT_END_LICENSE$
    **
    ****************************************************************************/
    
    #include <QtCore>
    #include <QtWidgets>
    
    QImage* im;
    QPixmap* pm;
    QGraphicsPixmapItem* gi;
    
    //![15]
    class StateSwitchEvent: public QEvent
    {
    public:
        StateSwitchEvent()
            : QEvent(Type(StateSwitchType))
        {
        }
    
        explicit StateSwitchEvent(int rand)
            : QEvent(Type(StateSwitchType)),
              m_rand(rand)
        {
        }
    
        enum { StateSwitchType = QEvent::User + 256 };
    
        int rand() const { return m_rand; }
    
    private:
        int m_rand;
    };
    //![15]
    
    //![16]
    class QGraphicsRectWidget : public QGraphicsWidget
    {
    public:
        void paint(QPainter *painter, const QStyleOptionGraphicsItem *,
                   QWidget *) Q_DECL_OVERRIDE
        {
            painter->fillRect(rect(), Qt::blue);
        }
    };
    //![16]
    
    class StateSwitchTransition: public QAbstractTransition
    {
    public:
        StateSwitchTransition(int rand)
            : QAbstractTransition(),
              m_rand(rand)
        {
        }
    
    protected:
    //![14]
        virtual bool eventTest(QEvent *event) Q_DECL_OVERRIDE
        {
            return (event->type() == QEvent::Type(StateSwitchEvent::StateSwitchType))
                && (static_cast<StateSwitchEvent *>(event)->rand() == m_rand);
        }
    //![14]
    
        virtual void onTransition(QEvent *) Q_DECL_OVERRIDE {}
    
    private:
        int m_rand;
    };
    
    //![10]
    class StateSwitcher : public QState
    {
        Q_OBJECT
    public:
        StateSwitcher(QStateMachine *machine)
            : QState(machine), m_stateCount(0), m_lastIndex(0)
        { }
    //![10]
    
    //![11]
        virtual void onEntry(QEvent *) Q_DECL_OVERRIDE
        {
            int n;
            while ((n = (qrand() % m_stateCount + 1)) == m_lastIndex)
            { }
            m_lastIndex = n;
            machine()->postEvent(new StateSwitchEvent(n));
        }
        virtual void onExit(QEvent *) Q_DECL_OVERRIDE {}
    //![11]
    
    //![12]
        void addState(QState *state, QAbstractAnimation *animation) {
            StateSwitchTransition *trans = new StateSwitchTransition(++m_stateCount);
            trans->setTargetState(state);
            addTransition(trans);
            trans->addAnimation(animation);
        }
    //![12]
    
    private:
        int m_stateCount;
        int m_lastIndex;
    };
    
    //![13]
    QState *createGeometryState(QObject *w1, const QRect &rect1,
                                QObject *w2, const QRect &rect2,
                                QObject *w3, const QRect &rect3,
                                QObject *w4, const QRect &rect4,
                                QState *parent)
    {
        QState *result = new QState(parent);
        result->assignProperty(w1, "geometry", rect1);
        result->assignProperty(w2, "geometry", rect2);
        result->assignProperty(w3, "geometry", rect3);
        result->assignProperty(w4, "geometry", rect4);
    
        return result;
    }
    //![13]
    
    class GraphicsView : public QGraphicsView
    {
        Q_OBJECT
    public:
        GraphicsView(QGraphicsScene *scene, QWidget *parent = NULL) : QGraphicsView(scene, parent)
        {
        }
    
    
    protected:
       virtual void mouseMoveEvent(QMouseEvent * event) Q_DECL_OVERRIDE
       {
           static uchar c = 0;
           c=c+0x20;
           uchar* pbits = im->bits();
           for(int i=0; i<1024*1024; i++)
           {
               pbits[i*4+0] =0xFF;
               pbits[i*4+1] =c;
               pbits[i*4+2] =0xFF;
               pbits[i*4+3] =0xFF;
           }
           //pm = new QPixmap( );
           //gi=new QGraphicsPixmapItem();
           gi->setPixmap(QPixmap::fromImage(*im, Qt::NoFormatConversion));
    
       }
        virtual void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE
        {
            fitInView(scene()->sceneRect());
            QGraphicsView::resizeEvent(event);
        }
    };
    
    #include <QtOpenGL/QGLWidget>
    
    int main(int argc, char **argv)
    {
        QApplication app(argc, argv);
    
    //![1]
        QGraphicsRectWidget *button1 = new QGraphicsRectWidget;
        QGraphicsRectWidget *button2 = new QGraphicsRectWidget;
        QGraphicsRectWidget *button3 = new QGraphicsRectWidget;
        QGraphicsRectWidget *button4 = new QGraphicsRectWidget;
        im = new QImage(1024,1024,QImage::Format_RGBA8888);
        uchar* pbits = im->bits();
        for(int i=0; i<1024*1024; i++)
        {
            pbits[i*4+0] =0xFF;
            pbits[i*4+1] =0x00;
            pbits[i*4+2] =0xFF;
            pbits[i*4+3] =0xFF;
        }
        //pm = new QPixmap( );
        gi=new QGraphicsPixmapItem();
        gi->setPixmap(QPixmap::fromImage(*im, Qt::NoFormatConversion));
        gi->setPos(0,0);
    
        button2->setZValue(1);
        button3->setZValue(2);
        button4->setZValue(3);
        QGraphicsScene scene(0, 0, 300, 300);
        scene.setBackgroundBrush(Qt::black);
    
        scene.addItem(gi);
        scene.addItem(button1);
        scene.addItem(button2);
        scene.addItem(button3);
        scene.addItem(button4);
    //![1]
        GraphicsView window(&scene);
        QGLWidget* gl = new QGLWidget();
        window.setViewport(gl);
    
        window.setFrameStyle(0);
        window.setAlignment(Qt::AlignLeft | Qt::AlignTop);
        window.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
        window.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    //![2]
        QStateMachine machine;
    
        QState *group = new QState();
        group->setObjectName("group");
        QTimer timer;
        timer.setInterval(1250);
        timer.setSingleShot(true);
        QObject::connect(group, SIGNAL(entered()), &timer, SLOT(start()));
    //![2]
    
    //![3]
        QState *state1;
        QState *state2;
        QState *state3;
        QState *state4;
        QState *state5;
        QState *state6;
        QState *state7;
    
        state1 = createGeometryState(button1, QRect(100, 0, 50, 50),
                                     button2, QRect(150, 0, 50, 50),
                                     button3, QRect(200, 0, 50, 50),
                                     button4, QRect(250, 0, 50, 50),
                                     group);
    //![3]
        state2 = createGeometryState(button1, QRect(250, 100, 50, 50),
                                     button2, QRect(250, 150, 50, 50),
                                     button3, QRect(250, 200, 50, 50),
                                     button4, QRect(250, 250, 50, 50),
                                     group);
        state3 = createGeometryState(button1, QRect(150, 250, 50, 50),
                                     button2, QRect(100, 250, 50, 50),
                                     button3, QRect(50, 250, 50, 50),
                                     button4, QRect(0, 250, 50, 50),
                                     group);
        state4 = createGeometryState(button1, QRect(0, 150, 50, 50),
                                     button2, QRect(0, 100, 50, 50),
                                     button3, QRect(0, 50, 50, 50),
                                     button4, QRect(0, 0, 50, 50),
                                     group);
        state5 = createGeometryState(button1, QRect(100, 100, 50, 50),
                                     button2, QRect(150, 100, 50, 50),
                                     button3, QRect(100, 150, 50, 50),
                                     button4, QRect(150, 150, 50, 50),
                                     group);
        state6 = createGeometryState(button1, QRect(50, 50, 50, 50),
                                     button2, QRect(200, 50, 50, 50),
                                     button3, QRect(50, 200, 50, 50),
                                     button4, QRect(200, 200, 50, 50),
                                     group);
    //![4]
        state7 = createGeometryState(button1, QRect(0, 0, 50, 50),
                                     button2, QRect(250, 0, 50, 50),
                                     button3, QRect(0, 250, 50, 50),
                                     button4, QRect(250, 250, 50, 50),
                                     group);
        group->setInitialState(state1);
    //![4]
    
    //![5]
        QParallelAnimationGroup animationGroup;
        QSequentialAnimationGroup *subGroup;
    
        QPropertyAnimation *anim = new QPropertyAnimation(button4, "geometry");
        anim->setDuration(1000);
        anim->setEasingCurve(QEasingCurve::OutElastic);
        animationGroup.addAnimation(anim);
    //![5]
    
    //![6]
        subGroup = new QSequentialAnimationGroup(&animationGroup);
        subGroup->addPause(100);
        anim = new QPropertyAnimation(button3, "geometry");
        anim->setDuration(1000);
        anim->setEasingCurve(QEasingCurve::OutElastic);
        subGroup->addAnimation(anim);
    //![6]
    
        subGroup = new QSequentialAnimationGroup(&animationGroup);
        subGroup->addPause(150);
        anim = new QPropertyAnimation(button2, "geometry");
        anim->setDuration(1000);
        anim->setEasingCurve(QEasingCurve::OutElastic);
        subGroup->addAnimation(anim);
    
        subGroup = new QSequentialAnimationGroup(&animationGroup);
        subGroup->addPause(200);
        anim = new QPropertyAnimation(button1, "geometry");
        anim->setDuration(1000);
        anim->setEasingCurve(QEasingCurve::OutElastic);
        subGroup->addAnimation(anim);
    
    //![7]
        StateSwitcher *stateSwitcher = new StateSwitcher(&machine);
        stateSwitcher->setObjectName("stateSwitcher");
        group->addTransition(&timer, SIGNAL(timeout()), stateSwitcher);
        stateSwitcher->addState(state1, &animationGroup);
        stateSwitcher->addState(state2, &animationGroup);
    //![7]
        stateSwitcher->addState(state3, &animationGroup);
        stateSwitcher->addState(state4, &animationGroup);
        stateSwitcher->addState(state5, &animationGroup);
        stateSwitcher->addState(state6, &animationGroup);
    //![8]
        stateSwitcher->addState(state7, &animationGroup);
    //![8]
    
    //![9]
        machine.addState(group);
        machine.setInitialState(group);
        machine.start();
    //![9]
    
        window.resize(300, 300);
        window.show();
    
        qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
    
        return app.exec();
    }
    
    #include "main.moc"
    
    

    Here I only added on scene QGrapchsiPixmapItem.
    Every time when mouse is moved on view (please press any mouse button) then Pixmap is updated with new image: gi->setPixmap(QPixmap::fromImage(*im, Qt::NoFormatConversion));

    Also note here

        GraphicsView window(&scene);
        QGLWidget* gl = new QGLWidget();
        window.setViewport(gl);
    

    This app has a memory leak in Windows 8.1 (I use it in VMWARE virtual machine ) but has no leak in Window 10.
    Endusers also complain on crash on WIndows 8.1 - I guess same memory leak.

    Besides that if OpenGL is not used then it works without issues.

    What I am doing wrong?
    Thanks in advance.

    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi and welcome to devnet,

      Why are you creating your im on the heap ? There's no need for that.

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      N 1 Reply Last reply
      0
      • SGaistS SGaist

        Hi and welcome to devnet,

        Why are you creating your im on the heap ? There's no need for that.

        N Offline
        N Offline
        nckma
        wrote on last edited by
        #3

        @SGaist
        yes, i know, but for this particular issue it does not matter.
        Can You please give me advice how properly setPixmap() to QGraphicsPixmapItem()?
        I belive this code

        gi->setPixmap(QPixmap::fromImage(*im, Qt::NoFormatConversion));
        

        should be correct, right?

        1 Reply Last reply
        0
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on last edited by
          #4

          On a second look, one thing is that calling bits like that triggers a deep copy of the pixel data which is a bad idea.

          If you want to be sure that there's a leak at some point you should really create a minimal compilable example that contains the minimum code to trigger the problem.

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          N 1 Reply Last reply
          0
          • SGaistS SGaist

            On a second look, one thing is that calling bits like that triggers a deep copy of the pixel data which is a bad idea.

            If you want to be sure that there's a leak at some point you should really create a minimal compilable example that contains the minimum code to trigger the problem.

            N Offline
            N Offline
            nckma
            wrote on last edited by
            #5

            @SGaist thank You for Your reply, I really do not know whom can I ask.
            Besdies that I do not think this is a deep copy issue.
            I have just commented out all bits() related code

            protected:
               virtual void mouseMoveEvent(QMouseEvent * event) Q_DECL_OVERRIDE
               {
                    /*
                   static uchar c = 0;
                   c=c+0x20;
                   uchar* pbits = im->bits();
                   for(int i=0; i<1024*1024; i++)
                   {
                       pbits[i*4+0] =0xFF;
                       pbits[i*4+1] =c;
                       pbits[i*4+2] =0xFF;
                       pbits[i*4+3] =0xFF;
                   }
                   */
                   gi->setPixmap(QPixmap::fromImage(*im, Qt::NoFormatConversion));
               }
            

            But I see issue is still there.
            Still huge memory leaks during mouse press and move.

            Second thing. Issue is very simple to avoid - just comment out OpenGL viewport:

                GraphicsView window(&scene);
                //QGLWidget* gl = new QGLWidget();
                //window.setViewport(gl);
            

            And that is all - no more memory leaks. This cannot be related to QImage.bits(), right?

            3rd thing. Issue happens only on some machines, not on every.
            I have one machine with windows 8 where this happens.
            On other Windows 8 machine this does not happen. On 3rd machine with windows10 this does not happen.

            I begin to think that this is either particular machine OpenGL drivers issue or missing some Windows updates related to graphcis. Can this be true?

            1 Reply Last reply
            0
            • SGaistS Offline
              SGaistS Offline
              SGaist
              Lifetime Qt Champion
              wrote on last edited by
              #6

              From your description, the driver installed could indeed be at fault. Application using OpenGL depends heavily on the drivers installed and this is nothing Qt specific. Thus if there's a bug in the driver, then application will appear as being buggy though they likely be innocent.

              Note that doing heavy processing and setting setting a pixmap in a function like mouseMoveEvent isn't a nice thing to do, this event will be triggered many times and quickly so you might be swamping your application yourself doing that.

              Interested in AI ? www.idiap.ch
              Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

              N 1 Reply Last reply
              0
              • SGaistS SGaist

                From your description, the driver installed could indeed be at fault. Application using OpenGL depends heavily on the drivers installed and this is nothing Qt specific. Thus if there's a bug in the driver, then application will appear as being buggy though they likely be innocent.

                Note that doing heavy processing and setting setting a pixmap in a function like mouseMoveEvent isn't a nice thing to do, this event will be triggered many times and quickly so you might be swamping your application yourself doing that.

                N Offline
                N Offline
                nckma
                wrote on last edited by
                #7

                @SGaist well,
                I have installed into VMWARE virtual machine fresh Windows 8.1 N - Updated from MSDN.
                VMWARE tools are installed.
                Trying same example with enabled OpenGL

                QGLWidget* gl = new QGLWidget();
                window.setViewport(gl);
                

                Any setPixmap() to QGraphicsPixmapItem on scene causes memory leak.
                Not setPixmap() exactly but maybe events triggered by setPixmap().
                Disabling OpenGL helps.

                I do not see any possibility to modify QGraphcisPixmapItem on scene on the fly.

                On windows 10 I do not see such issue, neither on real HW computer nor in VMWARE machine with win10.
                Feel myself stupid - cannot resolve this issue.

                Bad thing is that application already distributed between users and some of them complain on crash (out of memory).

                1 Reply Last reply
                0
                • SGaistS Offline
                  SGaistS Offline
                  SGaist
                  Lifetime Qt Champion
                  wrote on last edited by
                  #8

                  Can you get a stack trace from that ?

                  Interested in AI ? www.idiap.ch
                  Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                  N 1 Reply Last reply
                  0
                  • A Offline
                    A Offline
                    Asperamanca
                    wrote on last edited by
                    #9

                    A leak in the OpenGL driver is a real possibility. I had one of those many years ago, and was lucky to get a fix by the graphics card vendor. Observe whether the leak occurs always on cards from the same chipset vendor. Consider that even VMWare has to rely on the underlying hardware drivers at some point, otherwise drawing would be rather slow.

                    Have you tried upgrading your VM (on which the leak occurs) to Win10? Does the leak occur then?

                    Back then, I decided to run my software without any hardware acceleration. I was lucky the performance was sufficient, so I could rely on the application to behave the same way on all target systems.

                    1 Reply Last reply
                    0
                    • SGaistS SGaist

                      Can you get a stack trace from that ?

                      N Offline
                      N Offline
                      nckma
                      wrote on last edited by
                      #10

                      @SGaist
                      I hope I found solution for bug in my app.
                      If I use

                      //QGLWidget* gl = new QGLWidget();
                      QOpenGLWidget* gl = new QOpenGLWidget();
                      window.setViewport(gl);
                      

                      then I do not see memory leaks in my app on WIndows 8.1.
                      One line of code changes everything..
                      I will do more tests on side effects..

                      1 Reply Last reply
                      0
                      • SGaistS Offline
                        SGaistS Offline
                        SGaist
                        Lifetime Qt Champion
                        wrote on last edited by
                        #11

                        Seeing QGLWidget I didn't realise that you were using Qt 5... QGLWidget has been deprecated in favour of QOpenGLWidget.

                        Interested in AI ? www.idiap.ch
                        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                        1 Reply Last reply
                        0

                        • Login

                        • Login or register to search.
                        • First post
                          Last post
                        0
                        • Categories
                        • Recent
                        • Tags
                        • Popular
                        • Users
                        • Groups
                        • Search
                        • Get Qt Extensions
                        • Unsolved