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. Thesourceof theLoaderis bound to a property from the C++ or Python side. I then have aQTimerset up to toggle the source between two different QML files. Depending on several factors, theLoaderwill 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
QObjects 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) twoQmlFileWrapperobjects (which areQObjects):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
sourceof myLoaderis bound to a property that gets a member of theQmlFileWrapper, so when that object eventually gets deleted, theLoader'ssourcecan no longer find it to get the QML file path.I added a connection to the object's
onDestroyto 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
newaQObjectand do not specify a parent, is it reasonable to think that it will never be deleted until I do it explicitly? - When the
Loaderchanges 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
QmlFileWrapperobjects. It's obviously not the case that, when theLoaderchanges itssource, theQmlFileWrappergets 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::MemoryManagerreferences 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
-
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. Thesourceof theLoaderis bound to a property from the C++ or Python side. I then have aQTimerset up to toggle the source between two different QML files. Depending on several factors, theLoaderwill 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
QObjects 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) twoQmlFileWrapperobjects (which areQObjects):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
sourceof myLoaderis bound to a property that gets a member of theQmlFileWrapper, so when that object eventually gets deleted, theLoader'ssourcecan no longer find it to get the QML file path.I added a connection to the object's
onDestroyto 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
newaQObjectand do not specify a parent, is it reasonable to think that it will never be deleted until I do it explicitly? - When the
Loaderchanges 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
QmlFileWrapperobjects. It's obviously not the case that, when theLoaderchanges itssource, theQmlFileWrappergets 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::MemoryManagerreferences 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!
@malocascio
Generally, there is no automagic deletion of a QObject.
Best to set a breakpoint in the destructor ofQmlFileWrapperand check the stack trace for the caller. - If I
-
@malocascio
Generally, there is no automagic deletion of a QObject.
Best to set a breakpoint in the destructor ofQmlFileWrapperand 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 ofQmlFileWrapperand 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'ssourceseveral 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!
-
@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 ofQmlFileWrapperand 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'ssourceseveral 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...