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