GC崩溃QML应用程序 [英] GC crashes QML-Application

查看:393
本文介绍了GC崩溃QML应用程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


不要害怕!这不是生产代码。这只是为了学习关于QML的新东西!我不追求'你不应该这样做 - 这样做'。我对QML的内部更感兴趣


考虑以下QML代码

 导入QtQuick 2.4 
导入QtQuick.Window 2.0

窗口{
id:root
width:800
height:600
visible:true
GridView {
width:800
height: 200
模型:4000
flow:GridView.FlowTopToBottom

委托:矩形{
id:myDelegate
宽度:100
身高:100
border.width:1
Column {
anchors.fill:parent
Text {
text:index
height:20
width: parent.width
}
Item {
id:frame0
hei ght: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
}
}

组件{
id:myComp
文本{
anchors.centerIn :parent
Component.onDestruction:console.log('Destroy'+ text)
}
}
}
}

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

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



其中一个是委托的父对象,另一个是父对象 null 它的生命是由JS-Engine决定的。它应该是垃圾收集,一旦没有指针了,指向它。



首先,我会把它们放在 frame Item ),显示(设置一个可视化的父级)。作为代表,这些框架被销毁。
这将和预期的一样销毁代理作为父代的动态创建的对象。另一个是(应该)留给垃圾收集者去做他的工作。



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



虽然文档不建议这样做,但它确实有助于调用GC manualy(激活 Component.onCompleted )。

所以在我看来,GC高估了它的能力,并且当它已经到了晚上时,它决定采取行动。



这可能是什么原因造成的?有没有办法让GC成为主动的?


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


解决方案


可能是什么原因为了这?有没有办法告诉GC是
先生?


原因是 buggy qtquick对象生命周期的实现。在这一点上,它不是一个JS的东西,而是一个qtquick的东西。很明显,不遵守其自己的规则 - 例如,它将在仍处于使用状态时用父级对象删除对象,从而导致严重的崩溃。你不能指望引用计数也能工作。这种行为可能发生在许多使用动态的场景中,它通常不会在平凡和静态的场景中表现出来。



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




  • 对于创建,您必须按顺序将对象传递给C ++端要调用 QQmlEngine :: setObjectOwnership(ojb,QQmlEngine :: CppOwnership); 就可以了,这基本上告诉qtquick甚至不想尝试,幸运的是,它假定为销毁,您必须将对象传递给C ++端以调用 obj-> deleteLater();



对我来说,这是个窍门,我不再因无明显原因而崩溃。使用自定义生命周期管理,远离股票功能。它为你提供了保证,只要你需要,对象就会保持活力,但它也不会停留在你想要的地方,这是另一个问题,虽然不是那么严重。当然,这消除了使用JS的便利因素,因为您必须放弃自动生命周期管理,并且对自己的代码更加勤奋和明确,但对此您可以做的事情不多。尽管这个bug在一年前被报告,并被视为 critical ,但没有一丝关于它的任何工作。因此,我认为严格,因为它的严重程度可能会更严格,因此在找到其原因并修复它时更像最低优先级。 b $ b

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

Consider the following QML-Code

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

It illustrates to some extent the MemoryManagement of QML when using dynamic ObjectCreation (JS). I have a ListView, that creates a few delegates, and lets me browse through them, creating new one on demand.

The trick is: When ever a new delegate is created, it uses the JavaScript Dynamic Object Creation to create two instances of an text-object.

One of them is parented to the delegate, the other one is parented to null and it's life is therefore determined by the JS-Engine. It should be garbage collected, once there is no pointer left, pointing towards it.

For the start, I will put both of them in a frame (Item), to display (setting a visual parent). As the delegate, those frames are destroyed. This will - as expected - destroy the dynamically created Object that has the delegate as parent, as well. The other one is (should be) left for the Garbage Collector to do his work.

And this is where it fails - sometimes the application crashes before the GC kicks in, sometimes it crashes, while the GC is trying to do its work.

Though it is not reccommended by the documentation, it does help, to call the GC manualy (activate the line commented out in Component.onCompleted).

So it seems to me, the GC overestimates it's abilities, and decides to kick in, when it is already to late.

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

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?

The reason for this is the 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 - for example, it will delete an object with a parent while still in use, resulting in a hard crash. You cannot expect reference counting to work as well. This behavior can occur in a number of scenarios that employ dynamism, it generally does not manifest in trivial and static scenarios.

The solution, as already outlined in the linked question, is to use manual object lifetime management. Use a set of new functions for the creation and deletion of objects.

  • for creation, you must pass the object to the C++ side in order to call QQmlEngine::setObjectOwnership(ojb, QQmlEngine::CppOwnership); on it, this basically tells qtquick "don't even bother trying", luckily at least this works as it is supposed
  • for destruction, you must pass the object to the C++ side in order to call obj->deleteLater();

For me this does the trick, I no longer get crashes for no apparent reason. Use the custom lifetime management and stay away from the stock functions for that. It gives you guarantees, that the object will stay alive as long as you need it, but also that it will not stay past the point where you want it gone, which is another problem, albeit not that severe. Of course, this eliminates the convenience factor of using JS, as you have to give up on automatic lifetime management and be a little more diligent and explicit with your own code, but there isn't much you can do about it. Even though the bug was reported almost a year ago and deemed critical, not a shred of work has been done about it whatsoever. Thus I assume that as critical as it may be in its severity, it is more like lowest priority when it comes to finding its cause and fixing it.

这篇关于GC崩溃QML应用程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆