gpt4 book ai didi

javascript - QML 垃圾收集删除仍在使用的对象

转载 作者:数据小太阳 更新时间:2023-10-29 03:57:59 39 4
gpt4 key购买 nike

我曾多次遇到过这个问题,对象是动态创建的,无论它们是用 QML 还是 C++ 创建的。对象在仍在使用时被删除,导致无缘无故的硬崩溃。这些对象一直被引用并成为其他对象的父对象,一直到根对象,所以我发现 QML 在它们的引用计数仍然高于零时删除这些对象很奇怪。

到目前为止,我找到的唯一解决方案是在 C++ 中创建对象并将所有权显式设置为 CPP,从而无法从 QML 中删除对象。

起初我认为这可能是育儿问题,因为我使用的是 QObject派生类,动态实例化的QML方法传递一个Item对于 parent ,而 QtObject甚至不带有父属性 - 它没有从 QObject 公开.

但后来我尝试使用 Qobject派生它公开并使用育儿,最后甚至尝试使用 Item只是为了确保对象的父对象正确,但这种行为仍然存在。

这是产生此行为的示例,不幸的是我无法将其压缩为单个源,因为 Component 的深层嵌套s 打破它:

// ObjMain.qml
Item {
property ListModel list : ListModel { }
Component.onCompleted: console.log("created " + this + " with parent " + parent)
Component.onDestruction: console.log("deleted " + this)
}

// Uimain.qml
Item {
id: main
width: childrenRect.width
height: childrenRect.height
property Item object
property bool expanded : true
Loader {
id: li
x: 50
y: 50
active: expanded && object && object.list.count
width: childrenRect.width
height: childrenRect.height
sourceComponent: listView
}
Component {
id: listView
ListView {
width: contentItem.childrenRect.width
height: contentItem.childrenRect.height
model: object.list
delegate: Item {
id: p
width: childrenRect.width
height: childrenRect.height
Component.onCompleted: Qt.createComponent("Uimain.qml").createObject(p, {"object" : o})
}
}
}
Rectangle {
width: 50
height: 50
color: "red"

MouseArea {
anchors.fill: parent
acceptedButtons: Qt.RightButton | Qt.LeftButton
onClicked: {
if (mouse.button == Qt.RightButton) {
expanded = !expanded
} else {
object.list.append({ "o" : Qt.createComponent("ObjMain.qml").createObject(object) })
}
}
}
}
}

// main.qml

Window {
visible: true
width: 1280
height: 720

ObjMain {
id: obj
}

Uimain {
object: obj
}
}

该示例是一个简单的对象树构建器,左侧按钮向节点添加叶子,右侧按钮折叠节点。重现该错误所需要的只是创建一个深度为 3 的节点,然后折叠并展开根节点,控制台输出显示:
qml: created ObjMain_QMLTYPE_0(0x1e15bb8) with parent QQuickRootItem(0x1e15ca8)
qml: created ObjMain_QMLTYPE_0(0x1e5afc8) with parent ObjMain_QMLTYPE_0(0x1e15bb8)
qml: created ObjMain_QMLTYPE_0(0x1e30f58) with parent ObjMain_QMLTYPE_0(0x1e5afc8)
qml: deleted ObjMain_QMLTYPE_0(0x1e30f58)
object无缘无故删除最深节点的 ,即使它是父节点的父节点 Item并在列表模型中的 JS 对象中引用。尝试向最深节点添加新节点会使程序崩溃。

行为是一致的,无论树的结构如何,只有第二层节点存活,当树折叠时所有更深的节点都丢失。

错误不在于用作存储的列表模型,我已经使用 JS 数组和 QList 进行了测试。并且对象仍然丢失。此示例仅使用列表模型来保存 C++ 模型的额外实现。到目前为止,我发现的唯一补救措施是完全拒绝 QML 对对象的所有权。尽管此示例产生了相当一致的行为,但在生产代码中,自发删除通常是完全任意的。

关于垃圾收集器 - 我之前测试过它,并注意到它非常自由 - 创建和删除 100 MB 内存的对象并没有触发垃圾收集以释放该内存,但在这种情况下只有少数值(value)几百字节的对象被仓促删除。

根据文档,不应删除具有父对象或被 JS 引用的对象,在我的情况下,两者都是有效的:

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()



正如 Filip 的回答中提到的,如果对象是由不在被删除的对象中的函数创建的,则不会发生这种情况,因此它可能与与 QML 对象关联的含糊提及的 JS 状态有关,但我本质上是至于删除的原因,仍然一无所知,所以这个问题实际上仍然没有答案。

任何想法是什么原因造成的?

更新:九个月后 this critical bug 上的开发仍然为零.同时,我发现了几个额外的场景,其中仍在使用的对象被删除,对象的创建位置无关紧要的场景以及简单地在主 qml 文件中创建对象的解决方法不适用。最奇怪的部分是对象在“未引用”时没有被销毁,而是在“重新引用”时被销毁。也就是说,当引用它们的视觉对象被销毁时,它们并没有被销毁,而是在它们被重新创建时被销毁。

好消息是,即使对于在 QML 中创建的对象,仍然可以将所有权设置为 C++,因此不会失去在 QML 中创建对象的灵活性。调用一个函数来保护和删除每个对象会带来一些不便,但至少可以避免 QtQuick 有问题的生命周期管理。不得不喜欢 QML 的“便利性”——被迫回到 手册 对象生命周期管理。

最佳答案

I've encountered this problem on several occasions, with objects created dynamically, regardless of whether they were created in QML or C++



对象只有在设置了 JavaScriptOwnership 时才会考虑进行垃圾回收,如果它们是
  • 由 JavaScript/QML 直接创建
  • 所有权明确设置为 JavaScriptOwnership
  • 该对象是从 Q_INVOKABLE 方法返回的,并且之前没有调用过 setObjectOwnership()。

  • 在所有其他情况下,假定对象归 C++ 所有,不考虑进行垃圾收集。

    At first I assumed it may be an issue with parenting, since I was using QObject derived classes, and the QML method of dynamic instantiation passes an Item for a parent, whereas QtObject doesn't even come with a parent property - it is not exposed from QObject.



    Qt 对象树与 Qml 对象树完全不同。 QML 只关心它自己的对象树。
        delegate: Item {
    id: p
    width: childrenRect.width
    height: childrenRect.height
    Component.onCompleted: Qt.createComponent("Uimain.qml").createObject(p, {"object" : o})
    }

    在委托(delegate)的 onCompleted 处理程序中动态创建的对象的组合必然会导致错误。

    当您折叠树时,代理会被销毁,并且它们的所有子代都会被销毁,其中包括您动态创建的对象。是否仍然存在对 child 的实时引用并不重要。

    本质上,您没有为树提供稳定的后备存储 - 它由一堆嵌套的委托(delegate)组成,可以随时消失。

    现在,在某些情况下,QML 拥有的对象会被意外删除:任何 C++ 引用都不算作垃圾收集器的引用;这包括 Q_PROPERTY。在这种情况下,您可以:
  • 明确设置 CppOwnership
  • 使用 QPointer<> 保存引用以处理消失的对象。
  • 在 QML 中保存对对象的显式引用。
  • 关于javascript - QML 垃圾收集删除仍在使用的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33792876/

    39 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com