QObjects are being deleted by a Loader
-
I noticed some odd behavior in my application, so I stripped it down to a very small test app to see what's going on. An example using both C++ and PySide6 can be found here. The organization of the app isn't the best because it's been ripped apart, so forgive some oddities.
The QML side of the app is really just a
Loader
. Thesource
of theLoader
is bound to a property from the C++ or Python side. I then have aQTimer
set up to toggle the source between two different QML files. Depending on several factors, theLoader
will do this for several iterations, but then eventually fail to load (it sometimes takes hundreds or thousands of iterations, which is why the timer has 10 ms iterations... it's hard to look at it flickering).I have dug into this, and I found that my
QObject
s are being deleted when I don't expect them to. This is easier to see in the C++ version. My root context object allocates (usingnew
) twoQmlFileWrapper
objects (which areQObject
s):auto h = new QmlFileWrapper("Home.qml"); auto o = new QmlFileWrapper("Other.qml");
My expectation, since I didn't set a parent for either object, is that those two objects will never be deleted unless I explicitly do so (or the application ends). The
source
of myLoader
is bound to a property that gets a member of theQmlFileWrapper
, so when that object eventually gets deleted, theLoader
'ssource
can no longer find it to get the QML file path.I added a connection to the object's
onDestroy
to prove that out, and sure enough, eventually one of those two objects gets deleted. If I change it so that those two QmlFileWrapper objects are children of another object with the lifetime of the whole application, it runs indefinitely:auto h = new QmlFileWrapper("Home.qml", this); auto o = new QmlFileWrapper("Other.qml", this);
So, there are several learning opportunities here:
- If I
new
aQObject
and do not specify a parent, is it reasonable to think that it will never be deleted until I do it explicitly? - When the
Loader
changes itssource
, does it destroy the QML object that had previously been loaded? - One thing to note is that the QML objects that get loaded contain a reference to one of those two
QmlFileWrapper
objects. It's obviously not the case that, when theLoader
changes itssource
, theQmlFileWrapper
gets immediately deleted, because this thing runs for hundreds/thousands of iterations before failing. However, it seems like the javascript memory manager does eventually decide to clean them up, because I have seen someQV4::MemoryManager
references while digging around in the stack traces.
Can anyone help me understand what's happening here? This happens in Qt 6.2.1 and 6.5.1. Thanks!
- If I
-
@malocascio
Generally, there is no automagic deletion of a QObject.
Best to set a breakpoint in the destructor ofQmlFileWrapper
and check the stack trace for the caller. -
@Axel-Spoerl said in QObjects are being deleted by a Loader:
@malocascio
Generally, there is no automagic deletion of a QObject.
Best to set a breakpoint in the destructor ofQmlFileWrapper
and check the stack trace for the caller.Hi Axel,
Thanks for getting back to me! I dug in deep and finally found out what the problem was. I was not aware of the concept of ownership for QML objects. While I was creating my wrapper objects in Python or C++, I wasn't giving them parents. So it seems like when I set a property in the loaded QML, the javascript engine was taking ownership of the wrappers that didn't have a parent. After changing the
Loader
'ssource
several times, the javascript engine did some cleanup and freed the wrapper objects.This makes sense, and the fix was simply to set a parent for my wrapper objects in Python or C++. Then the javascript engine doesn't try to clean them up. This was a valuable lesson to learn!
Thanks!
-
@malocascio
Good morning,
thanks for sharing the solution! You found it yourself, I wasn't of much help here...