GC 使 QML 应用程序崩溃

GC crashes QML-Application

Do not fear! This is not production code. It is just to learn new things about QML! I do not seek 'you shall not do something like this - do it like that.' I am more interested in the internals of QML

考虑以下 QML 代码

import QtQuick 2.4
import QtQuick.Window 2.0

Window {
    id: root
    width: 800
    height: 600
    visible: true
    GridView {
        width: 800
        height: 200
        model: 4000
        flow: GridView.FlowTopToBottom

        delegate: Rectangle {
            id: myDelegate
            width: 100
            height: 100
            border.width: 1
            Column {
                anchors.fill: parent
                Text {
                    text: index
                    height: 20
                    width: parent.width
                }
                Item {
                    id: frame0
                    height: 20
                    width: parent.width
                }
                Item {
                    id: frame1
                    height: 20
                    width: parent.width
                }
            }

            Component.onCompleted: {
                // if (index % 100 === 0) gc()
                frame0.children = [myComp.createObject(myDelegate)]
                frame1.children = [myComp.createObject(null)]
                frame0.children[0].text = 'QML ' + index

                frame1.children[0].text = 'JS ' + index
            }
        }

        Component {
            id: myComp
            Text {
                anchors.centerIn: parent
                Component.onDestruction: console.log('Destroy ' + text)
            }
        }
    }
}

一定程度上说明了QML在使用动态ObjectCreation(JS)时的MemoryManagement。 我有一个 ListView,它创建了一些代表,让我浏览它们,按需创建新的代表。

诀窍是:每当创建新委托时,它都会使用 JavaScript 动态对象创建来创建文本对象的两个实例。

其中一个是委托的父级,另一个是 null 的父级,因此它的寿命由 JS 引擎决定。一旦没有指针指向它,它应该被垃圾收集。

首先,我将把它们都放在一个 frame (Item) 中,以显示(设置视觉父级)。作为代表,这些框架被销毁。 正如预期的那样,这也将销毁将委托作为父对象的动态创建的对象。另一个(应该)留给垃圾收集器来完成他的工作。

这就是它失败的地方 - 有时应用程序在 GC 启动之前崩溃,有时它崩溃,而 GC 正在尝试完成它的工作。

虽然文档不推荐,但手动调用 GC 确实有帮助(激活 Component.onCompleted 中注释掉的行)。

所以在我看来,GC 高估了它的能力,并决定在已经晚了的时候开始。

这可能是什么原因?有没有办法告诉 GC 更主动主动?

Again: I do not intend to use the Dynamic Object Creation with .createObject(null) in my code. It is pure curiosity.

What might be the reason for this? Is there a way to tell the GC to be mor proactive?

原因是buggy qtquick object lifetime implementation. At this point it doesn't look to be a JS thing, but a qtquick thing. It clearly doesn't abide to its own alleged rules - 例如,它会删除一个仍在使用中的父对象,导致硬崩溃。您不能指望引用计数也能正常工作。这种行为可能发生在许多使用动态的场景中,它通常不会出现在琐碎和静态的场景中。

如链接问题中所述,解决方案是使用手动对象生命周期管理。使用一组新函数来创建和删除对象。

  • 对于创建,您必须将对象传递给 C++ 端才能调用 QQmlEngine::setObjectOwnership(ojb, QQmlEngine::CppOwnership);,这基本上告诉 qtquick "don't even bother trying",幸运的是至少它按预期工作
  • 为了销毁,必须将对象传给C++端才能调用obj->deleteLater();

对我来说,这很有效,我不会再无缘无故地崩溃了。使用自定义生命周期管理并为此远离库存功能。它向您保证,只要您需要它,该对象就会保持活动状态,而且它不会停留在您希望它消失的地方,这是另一个问题,尽管没那么严重。当然,这消除了使用 JS 的便利因素,因为您必须放弃自动生命周期管理,并且对自己的代码更加勤奋和明确,但您对此无能为力。尽管该错误几乎是在一年前报告的,并且被认为是 严重 ,但没有对它进行任何工作。因此,我假设 critical 在其严重性方面,它更像是 lowest priority 来查找其原因并修复它.