QML garbage collection deletes objects still in use

后端 未结 3 1166
感动是毒
感动是毒 2020-11-29 11:23

I\'ve encountered this problem on several occasions, with objects created dynamically, regardless of whether they were created in QML or C++. The objects are deleted while s

相关标签:
3条回答
  • 2020-11-29 11:57

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

    Objects are only considered for garbage collection if they have JavaScriptOwnership set, which is the case if they are

    1. Directly created by JavaScript/QML
    2. Ownership is explicitly set to JavaScriptOwnership
    3. The object is returned from a Q_INVOKABLE method and didn't have setObjectOwnership() called on it previously.

    In all other cases objects are assumed to be owned by C++ and not considered for garbage collection.

    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.

    The Qt object tree is completely different from the Qml object tree. QML only cares about its own object tree.

        delegate: Item {
            id: p
            width: childrenRect.width
            height: childrenRect.height
            Component.onCompleted: Qt.createComponent("Uimain.qml").createObject(p, {"object" : o})
        }
    

    The combination of dynamically created objects in the onCompleted handler of a delegate is bound to lead to bugs.

    When you collapse the tree, the delegates get destroyed, and with them all of their children, which includes your dynamically created objects. It doesn't matter if there are still live references to the children.

    Essentially you've provided no stable backing store for the tree - it consists of a bunch of nested delegates which can go away at any time.

    Now, there are some situations where QML owned objects are unexpectedly deleted: any C++ references don't count as a ref for the garbage collector; this includes Q_PROPERTYs. In this case, you can:

    1. Set CppOwnership explicitly
    2. Use QPointer<> to hold the reference to deal with objects going away.
    3. Hold an explicit reference to the object in QML.
    0 讨论(0)
  • 2020-11-29 12:00

    Create an array inside of a .js file and then create an instance of that array with var myArray = []; on the top-level of that .js. file.

    Now you can reference any object that you append to myArray including ones that are created dynamically.

    Javascript vars are not deleted by garbage collection as long as they remain defined, so if you define one as a global object then include that Javascript file in your qml document, it will remain as long as the main QML is in scope.


    In a file called: backend.js

    var tiles = [];
    
    function create_square(new_square) {
        var component = Qt.createComponent("qrc:///src_qml/src_game/Square.qml");
        var sq = component.createObject(background, { "backend" : new_square });
        sq.x = new_square.tile.x
        sq.y = new_square.tile.y
        sq.width = new_square.tile.width;
        sq.height = new_square.tile.height;
        tiles[game.board.getIndex(new_square.tile.row, new_square.tile.col)] = sq;
        sq.visible = true;
    }
    

    EDIT :

    Let me explain a little more clearly how this could apply to your particular tree example.

    By using the line property Item object you are inadvertently forcing it to be a property of Item, which is treated differently in QML. Specifically, properties fall under a unique set of rules in terms of garbage collections, since the QML engine can simply start removing properties of any object to decrease the memory required to run.

    Instead, at the top of your QML document, include this line:

    import "./object_file.js" as object_file
    

    Then in the file object_file.js , include this line:

     var object_hash = []; 
    

    Now you can use object_hash any time to save your dynamically created components and prevent them from getting wiped out by referencing the

    object_file.object_hash

    object.

    No need to go crazy changing ownership etc

    0 讨论(0)
  • 2020-11-29 12:10

    QML is not C++ in a way of managing memory. QML is intended to take care about allocating memory and releasing it. I think the problem you found is just the result of this.

    If dynamic object creation goes too deep everything seems to be deleted. So it does not matter that your created objects were a part of the data - they are destroyed too.

    Unfortunately my knowledge ends here.

    One of the work arounds to the problem (proving my previous statement) is moving the creation of data structure out from the dynamic UI qml files:

    1. Place object creating function for example in main.qml

    function createNewObject(parentObject) {
        parentObject.list.append({ "o" : Qt.createComponent("ObjMain.qml").createObject(parentObject) })
    }
    
    1. Use this function instead in your code:

    // fragment of the Uimain.qml file
        MouseArea {
            anchors.fill: parent
            acceptedButtons: Qt.RightButton | Qt.LeftButton
            onClicked: {
                if (mouse.button == Qt.RightButton) {
                    expanded = !expanded
                } else {
                    createNewObject(object)
                }
            }
        }
    
    0 讨论(0)
提交回复
热议问题