When to delete QAbstractListModel created in C++ and used in QML
-
In our application, we create, in C++, a lot of QAbstractListModel and they are used in QML. We want to
- delete the models in C++ when they are not used anymore in QML (to reduce memory consumption)
- update the models (when needed) in C++ when they are still used in QML
What is the best way to achieve this?
I’ve tried setting JavaScriptOwnership on the models with
QQmlEngine::setObjectOwnership(model, QQmlEngine::JavaScriptOwnership)
and hence relying on the JavaScript Garbage collection to clean up the models when they are not used anymore by QML.Hence, in C++, before updating the model, I should check that the model still exists (and that it won’t get garbage collected while I’m updating it).
Could the following work:- we detect in a background thread that an update to a model is needed and emit a signal
- connect, from the main UI thread, to this signal
- in the slot, we check whether the model still exist
- if so, change ownership to Cpp again
- update the model
- after updating, change ownership to Qml again.
But is it possible that garbage collection kicks in between step 3 and 4 ? Does this approach seems fine?
An alternative could be to implement, in QML,
Component.onDestruction
and in there, tell C++ that the model can be deleted. This should work I guess but then our memory mgmt is dependent on a correct implementation in QMLFeedback appreciated!
Marc
-
Hello,
I don't work with QML, but I don't get what's the problem here. Just deleting the model(s) from C++ doesn't work? it should in principle. I don't get why would you want to start a whole tread just to delete an object (which, by the way, should be deleted from the thread its living in).Kind regards.
-
Hello,
I don't work with QML, but I don't get what's the problem here. Just deleting the model(s) from C++ doesn't work? it should in principle. I don't get why would you want to start a whole tread just to delete an object (which, by the way, should be deleted from the thread its living in).Kind regards.
@kshegunov I can only delete the model in C++ when the QML component does not need it anymore. So we need some input from QML:
- QML can either make an explicit call to C++ indicating that it doesn't need the model anymore (my second option) or
- we can let the javascript garbage collection clean up the model
The javascript-garbage-collection-based option seemed elegant at first but might become tricky when the C++ code wants to update the model (eg because some additional entries should be added).
I'm not sure though where you read that I wanted to create a thread to delete the object.
-
@kshegunov I can only delete the model in C++ when the QML component does not need it anymore. So we need some input from QML:
- QML can either make an explicit call to C++ indicating that it doesn't need the model anymore (my second option) or
- we can let the javascript garbage collection clean up the model
The javascript-garbage-collection-based option seemed elegant at first but might become tricky when the C++ code wants to update the model (eg because some additional entries should be added).
I'm not sure though where you read that I wanted to create a thread to delete the object.
@MarcVanDaele said:
I'm not sure though where you read that I wanted to create a thread to delete the object.
I suppose I misunderstood your first point from the list.
QML can either make an explicit call to C++ indicating that it doesn't need the model anymore (my second option)
What do you call an "explicit" call? As I see it the most painless option is to have a signal from QML, subscribe to that signal in some
QObject
instance and delete the model(s). This should work pretty painlessly, right?we can let the javascript garbage collection clean up the model
I'm not sure this is even an option. As far as I understand it, each QML entity corresponds to a C++ object and the QML engine runs the
qml
file and parses it. In the end the javascript garbage collector may run, or may not, depending on the underlying parser, so this doesn't sound to be very reliable. -
@MarcVanDaele said:
I'm not sure though where you read that I wanted to create a thread to delete the object.
I suppose I misunderstood your first point from the list.
QML can either make an explicit call to C++ indicating that it doesn't need the model anymore (my second option)
What do you call an "explicit" call? As I see it the most painless option is to have a signal from QML, subscribe to that signal in some
QObject
instance and delete the model(s). This should work pretty painlessly, right?we can let the javascript garbage collection clean up the model
I'm not sure this is even an option. As far as I understand it, each QML entity corresponds to a C++ object and the QML engine runs the
qml
file and parses it. In the end the javascript garbage collector may run, or may not, depending on the underlying parser, so this doesn't sound to be very reliable.@kshegunov QML can indeed either send a signal or make a function call to C++, indicating that the model is not in use anymore. Only drawback is that the C++ layer has to rely on the QML layer that this signal is sent/this function is called.
Using the javascript garbage collection is possible. When creating a
QObject
in C++, we can transfer ownership from C++ to QML. By doing so, the object will be garbage collected in QML/Javascript when not needed anymore. This approach seemed elegant and doesn't have the drawback listed above but it becomes tricky when the C++ layer still wants to update this model.But probably it is not a good design to transfer ownership to JS/QML and to still update the model afterwards in C++ so I'll stick with the explicit call from QML to C++.
-
@kshegunov QML can indeed either send a signal or make a function call to C++, indicating that the model is not in use anymore. Only drawback is that the C++ layer has to rely on the QML layer that this signal is sent/this function is called.
Using the javascript garbage collection is possible. When creating a
QObject
in C++, we can transfer ownership from C++ to QML. By doing so, the object will be garbage collected in QML/Javascript when not needed anymore. This approach seemed elegant and doesn't have the drawback listed above but it becomes tricky when the C++ layer still wants to update this model.But probably it is not a good design to transfer ownership to JS/QML and to still update the model afterwards in C++ so I'll stick with the explicit call from QML to C++.
Only drawback is that the C++ layer has to rely on the QML layer that this signal is sent/this function is called.
Well, someone has to tell the cleanup routines that the object is not needed anymore, it might as well be the user programmer (QML developer).
By doing so, the object will be garbage collected in QML/Javascript when not needed anymore.
That's the vague point. When does this happen? Is it immediately when the JS object goes out of scope, or is it put in a queue and the engine frees it when it sees fit (as Java'd ordinarily do)? Additionally, as you said, it's not a good idea to hold references to objects that might get deleted at any time (although a
QPointer
should help with that).so I'll stick with the explicit call from QML to C++.
This is what I'd do.
Kind regards.