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 来查找其原因并修复它.
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 来查找其原因并修复它.