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

[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.



  • @mbarclaygmail-com In Qt5 QImage has a clean up function.

    You can provide a function pointer cleanupFunction along with an extra pointer cleanupInfo that will be called when the last copy is destroyed.


Log in to reply