GNOME Bugzilla – Bug 771326
Fix memory leak: QCoreApplication::postEvent with DeactivateEvent never execute.
Last modified: 2016-09-15 06:37:18 UTC
Created attachment 335407 [details] [review] Patch to fix memory leak: QCoreApplication::postEvent with DeactivateEvent never execute. Hi, I found a problem during restart the video in qt quick application using QtGstreamer. In my pc this problem occur and so I don't have any critical problem, but on some i.MX6 board occurs memory leak in DMA allocation. This problem occurs because 'DeactivateEvent' scheduled by 'postEvent' is never executed. Please see log at end: 'qt-gstreamer-fail.txt'. There you can see that after 'Deactivating' it never writes the log 'Received deactivate event', simply this event is lost. To fix this, I replaced method postEvent with sendEvent. Please see log at end: 'qt-gstreamer-ok.txt'. After this fix, the 'Received deactivate event' always occurs after 'Deactivating'. I created an application to make a test: https://github.com/Danfx/qtteste/tree/master/QuickTest Also a pull request of correction: https://github.com/GStreamer/qt-gstreamer/pull/1 Please, comment. Best Regards, Daniel Fussia. ICC - Inatel Competence Center ---------------- qt-gstreamer-fail.txt ------------------------- [fedora@localhost build-QuickTest-Desktop-Debug]$ GST_DEBUG=qt5videosink:6 ./QuickTest QML debugging is enabled. Only use this in a safe environment. Stopping Playing 0:00:02.357603234 31450 0x7fcb0c002b20 INFO qt5videosink /home/fedora/env/qt-gstreamer/git/pc/qt-gstreamer/elements/gstqtvideosink/delegates/basedelegate.cpp:54:setActive:<qtquick2videosink0> Activating 0:00:02.379428102 31450 0x7fcafc26f450 LOG qt5videosink /home/fedora/env/qt-gstreamer/git/pc/qt-gstreamer/elements/gstqtvideosink/gstqtquick2videosink.cpp:233:gst_qt_quick2_video_sink_set_caps:<qtquick2videosink0> new caps video/x-raw, format=(string)I420, width=(int)640, height=(int)480, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, colorimetry=(string)bt601, framerate=(fraction)0/1 0:00:02.397144289 31450 0x1eff4d0 INFO qt5videosink /home/fedora/env/qt-gstreamer/git/pc/qt-gstreamer/elements/gstqtvideosink/delegates/qtquick2videosinkdelegate.cpp:33:updateNode:<qtquick2videosink0> creating new VideoNode 0:00:02.397212117 31450 0x1eff4d0 LOG qt5videosink /home/fedora/env/qt-gstreamer/git/pc/qt-gstreamer/elements/gstqtvideosink/delegates/qtquick2videosinkdelegate.cpp:78:updateNode:<qtquick2videosink0> Recalculated paint areas: Frame size: (640 x 480), target area: (x: 0,000000, y: 0,000000, w: 640,000000, h: 480,000000), video area: (x: 0,000000, y: 0,000000, w: 640,000000, h: 480,000000), black1: (x: 0,000000, y: 0,000000, w: 0,000000, h: 0,000000), black2: (x: 0,000000, y: 0,000000, w: 0,000000, h: 0,000000) Stopping 0:00:03.740933649 31450 0x1eff4d0 INFO qt5videosink /home/fedora/env/qt-gstreamer/git/pc/qt-gstreamer/elements/gstqtvideosink/delegates/basedelegate.cpp:54:setActive:<qtquick2videosink0> Deactivating Playing 0:00:04.033478734 31450 0x7fcb2001e450 INFO qt5videosink /home/fedora/env/qt-gstreamer/git/pc/qt-gstreamer/elements/gstqtvideosink/delegates/basedelegate.cpp:54:setActive:<qtquick2videosink1> Activating 0:00:04.055639390 31450 0x7fcb2001e370 LOG qt5videosink /home/fedora/env/qt-gstreamer/git/pc/qt-gstreamer/elements/gstqtvideosink/gstqtquick2videosink.cpp:233:gst_qt_quick2_video_sink_set_caps:<qtquick2videosink1> new caps video/x-raw, format=(string)I420, width=(int)640, height=(int)480, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, colorimetry=(string)bt601, framerate=(fraction)0/1 0:00:04.068494286 31450 0x1eff4d0 INFO qt5videosink /home/fedora/env/qt-gstreamer/git/pc/qt-gstreamer/elements/gstqtvideosink/delegates/qtquick2videosinkdelegate.cpp:33:updateNode:<qtquick2videosink1> creating new VideoNode 0:00:04.068560875 31450 0x1eff4d0 LOG qt5videosink /home/fedora/env/qt-gstreamer/git/pc/qt-gstreamer/elements/gstqtvideosink/delegates/qtquick2videosinkdelegate.cpp:78:updateNode:<qtquick2videosink1> Recalculated paint areas: Frame size: (640 x 480), target area: (x: 0,000000, y: 0,000000, w: 640,000000, h: 480,000000), video area: (x: 0,000000, y: 0,000000, w: 640,000000, h: 480,000000), black1: (x: 0,000000, y: 0,000000, w: 0,000000, h: 0,000000), black2: (x: 0,000000, y: 0,000000, w: 0,000000, h: 0,000000) Stopping 0:00:06.882400786 31450 0x1eff4d0 INFO qt5videosink /home/fedora/env/qt-gstreamer/git/pc/qt-gstreamer/elements/gstqtvideosink/delegates/basedelegate.cpp:54:setActive:<qtquick2videosink1> Deactivating [fedora@localhost build-QuickTest-Desktop-Debug]$ ---------------------------------------------------------------- ---------------- qt-gstreamer-ok.txt ------------------------- [fedora@localhost build-QuickTest-Desktop-Debug]$ GST_DEBUG=qt5videosink:6 ./QuickTest QML debugging is enabled. Only use this in a safe environment. Stopping Playing 0:00:01.700519287 30893 0x7f2c14002720 INFO qt5videosink /home/fedora/env/qt-gstreamer/git/pc/qt-gstreamer/elements/gstqtvideosink/delegates/basedelegate.cpp:54:setActive:<qtquick2videosink0> Activating 0:00:01.719814604 30893 0x7f2c0c26acf0 LOG qt5videosink /home/fedora/env/qt-gstreamer/git/pc/qt-gstreamer/elements/gstqtvideosink/gstqtquick2videosink.cpp:233:gst_qt_quick2_video_sink_set_caps:<qtquick2videosink0> new caps video/x-raw, format=(string)I420, width=(int)640, height=(int)480, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, colorimetry=(string)bt601, framerate=(fraction)0/1 0:00:01.735452508 30893 0x149a4d0 INFO qt5videosink /home/fedora/env/qt-gstreamer/git/pc/qt-gstreamer/elements/gstqtvideosink/delegates/qtquick2videosinkdelegate.cpp:33:updateNode:<qtquick2videosink0> creating new VideoNode 0:00:01.735518797 30893 0x149a4d0 LOG qt5videosink /home/fedora/env/qt-gstreamer/git/pc/qt-gstreamer/elements/gstqtvideosink/delegates/qtquick2videosinkdelegate.cpp:78:updateNode:<qtquick2videosink0> Recalculated paint areas: Frame size: (640 x 480), target area: (x: 0,000000, y: 0,000000, w: 640,000000, h: 480,000000), video area: (x: 0,000000, y: 0,000000, w: 640,000000, h: 480,000000), black1: (x: 0,000000, y: 0,000000, w: 0,000000, h: 0,000000), black2: (x: 0,000000, y: 0,000000, w: 0,000000, h: 0,000000) Stopping 0:00:03.871434908 30893 0x149a4d0 INFO qt5videosink /home/fedora/env/qt-gstreamer/git/pc/qt-gstreamer/elements/gstqtvideosink/delegates/basedelegate.cpp:54:setActive:<qtquick2videosink0> Deactivating 0:00:03.871636393 30893 0x149a4d0 LOG qt5videosink /home/fedora/env/qt-gstreamer/git/pc/qt-gstreamer/elements/gstqtvideosink/delegates/basedelegate.cpp:184:event:<qtquick2videosink0> Received deactivate event Playing 0:00:03.883428503 30893 0x149a4d0 INFO qt5videosink /home/fedora/env/qt-gstreamer/git/pc/qt-gstreamer/elements/gstqtvideosink/delegates/qtquick2videosinkdelegate.cpp:33:updateNode:<qtquick2videosink1> creating new VideoNode 0:00:04.039055176 30893 0x7f2c34022ca0 INFO qt5videosink /home/fedora/env/qt-gstreamer/git/pc/qt-gstreamer/elements/gstqtvideosink/delegates/basedelegate.cpp:54:setActive:<qtquick2videosink1> Activating 0:00:04.077142529 30893 0x7f2c34022b70 LOG qt5videosink /home/fedora/env/qt-gstreamer/git/pc/qt-gstreamer/elements/gstqtvideosink/gstqtquick2videosink.cpp:233:gst_qt_quick2_video_sink_set_caps:<qtquick2videosink1> new caps video/x-raw, format=(string)I420, width=(int)640, height=(int)480, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, colorimetry=(string)bt601, framerate=(fraction)0/1 0:00:04.090962575 30893 0x149a4d0 LOG qt5videosink /home/fedora/env/qt-gstreamer/git/pc/qt-gstreamer/elements/gstqtvideosink/delegates/qtquick2videosinkdelegate.cpp:78:updateNode:<qtquick2videosink1> Recalculated paint areas: Frame size: (640 x 480), target area: (x: 0,000000, y: 0,000000, w: 640,000000, h: 480,000000), video area: (x: 0,000000, y: 0,000000, w: 640,000000, h: 480,000000), black1: (x: 0,000000, y: 0,000000, w: 0,000000, h: 0,000000), black2: (x: 0,000000, y: 0,000000, w: 0,000000, h: 0,000000) Stopping 0:00:11.963099503 30893 0x149a4d0 INFO qt5videosink /home/fedora/env/qt-gstreamer/git/pc/qt-gstreamer/elements/gstqtvideosink/delegates/basedelegate.cpp:54:setActive:<qtquick2videosink1> Deactivating 0:00:11.963297834 30893 0x149a4d0 LOG qt5videosink /home/fedora/env/qt-gstreamer/git/pc/qt-gstreamer/elements/gstqtvideosink/delegates/basedelegate.cpp:184:event:<qtquick2videosink1> Received deactivate event [fedora@localhost build-QuickTest-Desktop-Debug]$ ----------------------------------------------------------------
I'm sorry, but this is wrong. There is a reason why the code calls postEvent() there instead of sendEvent(). With your patch, the event delivery becomes synchronous, which means that the thread that executes the element's state change will also deliver the event in the context of the state change. This is wrong because in GStreamer you cannot guarantee that the thread which executes the state change is the same as the main GUI thread, and in case the event is delivered in the wrong thread, the event loop will most likely crash (sendEvent() is *not* thread-safe). postEvent() on the other hand ensures that the event delivery happens in the correct thread, no matter which thread the event was sent from. The real problem in your example is that your pipeline changes state to Null *after* the event loop terminates! The ~Player() destructor is called when main() terminates, after QCoreApplication::exec() has returned, so it is reasonable in this case for a leak to happen, since the event is posted to a non-existent event loop. It is generally a bad practice in Qt applications to allocate objects on the stack in main() because of that. Instead, allocate it on the heap and hook its destruction to the QCoreApplication::aboutToQuit() signal. This will ensure that everything cleans up properly before the event loop terminates.
Oh and let me not forget that the async event delivery in this code exists in the first place exactly because the sink's drawing must happen in the GUI thread. This is the only way to guarantee the thread in which the drawing operations will execute.