GC 使 QML 应用程序崩溃

GC crashes QML-Application

本文关键字:崩溃 应用程序 QML GC      更新时间:2023-09-26

不要害怕!这不是生产代码。这只是为了学习有关QML的新知识! 我不寻求'你不要做这样的事情——那样做'。 我对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)
            }
        }
    }
}

它在一定程度上说明了使用动态对象创建(JS(时QML的内存管理。我有一个ListView,它创建了一些委托,并让我浏览它们,按需创建新的代表。

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

其中一个是委托的父级,另一个是null的父级,因此它的生命周期由 JS-Engine 决定。一旦没有指针,它应该被垃圾回收,指向它。

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

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

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

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

这可能是什么原因?有没有办法告诉总理事会积极主动

再次:我不打算在我的代码中使用带有.createObject(null)的动态对象创建。这是纯粹的好奇心。

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

其原因是有缺陷的qtquick对象生命周期实现。在这一点上,它看起来不是JS的东西,而是一个qtquick的东西。它显然不遵守自己所谓的规则 - 例如,它会删除仍在使用中的父对象,从而导致硬崩溃。您不能指望引用计数也能正常工作。此行为可能发生在许多采用动态的方案中,它通常不会在琐碎和静态方案中表现出来。

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

  • 对于创建,您必须将对象传递给C++端才能在其上调用QQmlEngine::setObjectOwnership(ojb, QQmlEngine::CppOwnership);,这基本上告诉 qtQuick"甚至不要费心尝试",幸运的是,至少这应该像它应该的那样工作
  • 对于销毁,您必须将对象传递给C++端才能调用obj->deleteLater();

对我来说,这确实可以解决问题,我不再无缘无故地崩溃。使用自定义生命周期管理并远离库存功能。它为您提供了保证,只要您需要它,该对象就会保持活动状态,但它也不会停留在您希望消失的点之后,这是另一个问题,尽管不是那么严重。当然,这消除了使用 JS 的便利因素,因为您必须放弃自动生命周期管理,并对自己的代码更加勤奋和明确,但对此您无能为力。尽管该错误在大约一年前被报告并被认为是关键的,但尚未对此进行任何工作。因此,我认为,尽管它的严重性可能很关键,但在找到原因和修复它时,它更像是最低优先级