[SOLVED] QDeclarativeImageProvider and memory leaks with QImage



  • Hello,

    I have a 3rd party library that is generating pixel buffers. I create a QImage with the buffer and return it to the GUI using QDeclarativeImageProvider. I am using QImage so the buffers can be generated asynchronously. The problem is: QImage doesn't take ownership of the buffer. But I'm returning a QImage to the GUI, and there's no telling how many times it will be copied as its passed around the QDeclarative library. How do I know when QImage is done referencing my buffer so I can delete it? Or, is it possible to create a QImage that owns its buffer and will release it automatically?

    Thanks,
    Matt



  • Hello,

    QImage uses "implicit data sharing":http://qt-project.org/doc/qt-4.8/implicit-sharing.html#implicit-data-sharing so you will only one copy of data. When last QImage that uses this data is destroyed data buffer will be released.



  • [quote author="MattB" date="1332203247"]Or, is it possible to create a QImage that owns its buffer and will release it automatically?[/quote]
    Subclass QImage and reimplement its destructor, which will delete the user-supplied buffer.

    [quote author="task_struct" date="1332246203"]Hello,
    QImage uses "implicit data sharing":http://qt-project.org/doc/qt-4.8/implicit-sharing.html#implicit-data-sharing so you will only one copy of data. When last QImage that uses this data is destroyed data buffer will be released.[/quote]
    This is not true for QImage using a user-supplied buffer.



  • [quote author="Lukas Geyer" date="1332247257"][quote author="MattB" date="1332203247"]Or, is it possible to create a QImage that owns its buffer and will release it automatically?[/quote]
    Subclass QImage and reimplement its destructor, which will delete the user-supplied buffer.[/quote]

    Won't this lead to the buffer being lost/deleted prematurely?

    @
    MyQImage MyProvider::requestImage(QString id, QSize *size, QSize requestedSize) {
    ...
    ...

    // Let's pretend this creates an 800x600 Image buffer
    uchar* data = generateSomeImageData();
    
    MyQImage image(data, 800, 600, QImage::Format_ARGB32);
    
    return image;
    

    }
    @

    Qt is expecting a QImage back from this method. If Qt does:

    @QImage image = provider->requestImage(id, &size, requestedSize);@

    Won't my custom data in MyQImage get sliced?

    Here's the line that's causing me problems:

    http://qt.gitorious.org/qt/qt/blobs/4.7/src/gui/image/qimage.cpp#line901

    I wonder if I can just do:

    @image->data_ptr()->own_data = true;@

    That should cause QImageData to delete the buffer when it destructs:

    http://qt.gitorious.org/qt/qt/blobs/4.7/src/gui/image/qimage.cpp#line263

    And that should happen when all QImage's that share the data have destructed.



  • [quote author="MattB" date="1332256874"]
    I wonder if I can just do:

    @image->data_ptr()->own_data = true;@
    [/quote]

    Heh, no I can't. That's not part of the Qt API (defined in qimage_p.h). Better drink some more coffee... :)



  • OK, looks like I found a solution:

    @MyQImage MyProvider::requestImage(QString id, QSize *size, QSize requestedSize) {
    ...
    ...

    // Let's pretend this creates an 800x600 Image buffer
    uchar* data = generateSomeImageData();
    
    QImage *source = new QImage(data, 800, 600, QImage::Format_ARGB32);
    QImage image(800, 600, QImage::Format_ARGB32);
    QPainter painter(&image);
    painter.drawImage(QPoint(0,0), *source);
    
    delete source;
    delete data;
    
    return image;
    

    }
    @

    My memory profile looks correct using this solution.



  • Well, that's cheap ;-) I thought that's exactly the behaviour you want to prevent - having an additional buffer - and you want to re-use the already existing buffer.

    If you just want to construct a QImage from some binary data use QImage::fromData() instead.

    [quote author="MattB" date="1332256874"]And that should happen when all QImage's that share the data have destructed.
    [/quote]
    Use QImage::isDetached() when deconstructing a QImage to find out if its buffer is still shared with another instance or if it is safe to delete the buffer.



  • Ideally, yes, I would avoid the buffer copy, but QImage::fromData() wants a buffer in one of the formats specified by QImageReader::supportedImageFormats() . None of those formats worked with my data, so I'm stuck with the QPainter approach.


Log in to reply
 

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