I have a C++ class that is exposed in QML as a singleton that produces other types
qmlRegisterSingletonType<DomainManager>("my.pkg", 1, 0, "DomainManager", domain_provider);
qmlRegisterUncreatableType<Control>("my.pkg", 1, 0, "Control", "Get it fresh from DomainManager");
The DomainManager
has a function
Q_INVOKABLE Control* controlWriter(QString partition);
According to http://doc.qt.io/qt-5/qtqml-cppintegration-data.html#data-ownership an object returned from a Q_INVOKABLE
is owned by QML and should be deleted by the GC. The only exception seems to be when a parent is set on the returned object, which is not the case.
I have a StackView
which contains panels with a property:
property Control ctrl: DomainManager.controlWriter(dummy.name)
I have verified that when I pop the panel off the stack, Component.onDestruction
gets called, so the panel does get deleted.
However, I put the following destructor on the C++ object, and it does not get deleted until the whole application exits.
~Control() { qDebug() << "deleting control"; };
The only way I've found to get rid of the Control
object is to call ctrl.destroy()
in Component.onDestruction
to manually free it.
Why does QML not free this object?
The full QML file holding the property is as follows. ctrl
is not used outside this file.
import QtQuick 2.11
import my.pkg 1.0
Image {
id: dummy
property string name
property Control ctrl: DomainManager.controlWriter(dummy.name)
source: "dummy.jpg"
fillMode: Image.PreserveAspectFit
Connections {
target: gamepad
onAxisLeftYChanged: {
ctrl.id = dummy.name
ctrl.x = gamepad.axisLeftY * 32767
ctrl.yaw = gamepad.axisLeftX * 32767
ctrl.publish()
}
onAxisLeftXChanged: {
ctrl.id = dummy.name
ctrl.x = gamepad.axisLeftY * 32767
ctrl.yaw = gamepad.axisLeftX * 32767
ctrl.publish()
}
}
Component.onDestruction: {
// not sure why this requires manual clean-up
ctrl.destroy()
}
}
Let's find out what's QML GC:
main.cpp
DomainManager *example = nullptr;
static QObject *domain_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
{
Q_UNUSED(engine)
Q_UNUSED(scriptEngine)
return example;
}
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
example = new DomainManager;
qmlRegisterSingletonType<DomainManager>("my.pkg", 1, 0, "DomainManager", domain_provider);
qmlRegisterUncreatableType<Control>("my.pkg", 1, 0, "Control", "Get it fresh from DomainManager");
QQmlApplicationEngine engine;
QObject::connect(example, &DomainManager::collectGarbage,
[&engine]() {
engine.collectGarbage();
qDebug("collectGarbage");
});
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
QML
Window
{
visible: true
height: 640
width: 480
Component {
id: test
Item {
property Control ctrl: DomainManager.controlWriter("test")
}
}
Component.onCompleted: {
var c = test.createObject()
console.log("Control created")
c.destroy()
//DomainManager.collectGarbage()
console.log("Window onCompleted")
}
}
In the above code, I add an additional signal collectGarbage
of DomainManager
to demonstrate GC.
The object is owned by JavaScript. When the object is returned to QML as the return value of a method call, QML will track it and delete it if there are no remaining JavaScript references to it and it has no QObject::parent().
qml: Control created qml: Window onCompleted
DomainManager.collectGarbage()
tells QML engine to collectGarbage
. The output will be: qml: Control created collectGarbage qml: Window onCompleted deleting control
control
object to Cpp QQmlEngine::setObjectOwnership(control, QQmlEngine::CppOwnership);
The output: qml: Control created collectGarbage qml: Window onCompleted
Conclusion:
The code demo shows what if I force release the garbage. GC is not the smart pointer. When the object's reference count becomes zero, QML GC will destroy the object which returns from Q_INVOKABLE
function except CppOwnership
. But not immediately. Which I consider it similar to Java GC.
collectGarbage:
Normally you don't need to call this function; the garbage collector will automatically be invoked when the QJSEngine decides that it's wise to do so (ie when a certain number of new objects have been created). However, you can call this function to explicitly request that garbage collection should be performed as soon as possible.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.