我有一个C ++类,该类在QML中以产生其他类型的单例形式公开
qmlRegisterSingletonType<DomainManager>("my.pkg", 1, 0, "DomainManager", domain_provider);
qmlRegisterUncreatableType<Control>("my.pkg", 1, 0, "Control", "Get it fresh from DomainManager");
DomainManager
具有功能
Q_INVOKABLE Control* controlWriter(QString partition);
根据http://doc.qt.io/qt-5/qtqml-cppintegration-data.html#data-ownership,从Q_INVOKABLE
返回的对象归QML所有,应由GC删除。唯一的例外似乎是在返回的对象上设置了父对象时,情况并非如此。
我有一个StackView
,其中包含具有属性的面板:
property Control ctrl: DomainManager.controlWriter(dummy.name)
我已验证,当我将面板弹出堆栈时,Component.onDestruction
会被调用,因此该面板确实会被删除。
但是,我将以下析构函数放在C ++对象上,直到整个应用程序退出,它都不会被删除。
~Control() { qDebug() << "deleting control"; };
我发现摆脱Control
对象的唯一方法是调用ctrl.destroy()
中的Component.onDestruction
来手动释放它。
为什么QML不释放该对象?
保存该属性的完整QML文件如下。 ctrl
不在此文件外部使用。
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()
}
}
答案 0 :(得分:0)
让我们找出什么是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")
}
}
在上面的代码中,我添加了collectGarbage
的附加信号DomainManager
来演示GC。
该对象归JavaScript所有。当对象返回到QML时 作为方法调用的返回值,QML将对其进行跟踪并删除它 如果没有剩余的JavaScript引用,并且没有 QObject :: parent()。
qml: Control created qml: Window onCompleted
DomainManager.collectGarbage()
告诉QML引擎collectGarbage
。
输出将是:qml: Control created collectGarbage qml: Window onCompleted deleting control
control
对象的所有权更改为Cpp QQmlEngine::setObjectOwnership(control, QQmlEngine::CppOwnership);
输出:qml: Control created collectGarbage qml: Window onCompleted
结论:
代码演示显示了如果我强制释放垃圾该怎么办。
GC 不是智能指针。当对象的引用计数变为零时,QML GC将销毁从Q_INVOKABLE
函数返回的对象,CppOwnership
除外。但不是立即。我认为它类似于Java GC。
collectGarbage:
通常,您不需要调用此函数;垃圾收集器 当QJSEngine决定 明智的做法是这样做(即当已经有一定数量的新对象 创建)。但是,您可以调用此函数来显式请求 应该尽快执行垃圾收集。