Artem Redko
Artem Redko

Reputation: 29

Memory of "property var" is not released in Android when deleting a created Qt.createComponent Qt QML component

main.qml

import QtQuick 2.14
import QtQuick.Window 2.12
import QtQuick.Controls 2.12

Window {
    id: window
    property variant name: []
    property var dialogObject
    Button{
        text: "open window1"
        onClicked: {
            var dialogComponent = Qt.createComponent("qrc:/Window1.qml");
            if (dialogComponent.status == Component.Ready) {
                dialogObject = dialogComponent.createObject(window);
                dialogObject.show()
            }
        }
    }
    Button{
        text: "add array"
        onClicked: {
            for (var i=1; i<10000000; i++){
                name.push(1000000000)
            }
        }
    }
    Button{
        text: "remove array"
        onClicked: delete name[10000000] //do not release!!!!!!!
    }
    Button{
        text: "remove array2"
        onClicked: delete name //do not release!!!!!!!!!!!!!!!!
    }
    Button{
        text: "remove array2"
        onClicked: name = null //do not release!!!!!!!!!!!!!!!
    }
}

Window1.qml

import QtQuick 2.0
import QtQuick.Controls 2.12
import QtQuick.Window 2.12
Window {
    id: window1
    property var name: [] //do not release!!!!!!!!!!!!!!!!!!!!
    Button{
        text: "destroy window1"
            onClicked: {
                window1.destroy()
            }
        }    
    Component.onCompleted: {
        for (var i=1; i<10000000; i++){
            name.push(1000000000)
        }
        console.log("window1 Component.onCompleted:")
    }
    Component.onDestruction: {
        console.log("window1 Component.onDestuction:")
    }
}

Memory of "property var" is not released in Android when deleting a created Qt.createComponent QML component. I monitor the allocation and deletion of memory and see that when the application loaded there were the following indicators:

When I had pressed the button "add array" - Unknown memory value changed and became 262780kb: After I had pressed "remove array" or "remove array2" - nothing changed and Unknown memory the same 262780kb. Memory is not released! If I pressed the button "open window1" the object of Window1 is created and in this time in object Window1 array "name" is had been assigned and memory parameter(Unknown) increase and become 524984kb: enter image description here When I press "destroy window1" button - the window is self destructed by call window1.destroy(), but memory is not changed and remain the same 524984kb. If I press "open window1" button more and more the Unknown memory value is increasing proportionally until the app crashes and is not released! I know that QML has own JS engine and own garbage collector, but when object window1 is has destructed the memory allocated for property var and all included components must released, but it is not happend. The device on which my app worked has small volume of memory and I have a big problem with that. It turns out that the memory is not freed when the object is destroyed. Is there some way to realese memory under property var? How is it to solve this issue with app(Unknown) memory increasing?

Upvotes: 0

Views: 119

Answers (2)

Artem Redko
Artem Redko

Reputation: 29

I jumped to conclusions gc() does not release the memory of the "property var", the only way I found to do this is to redefine the variable "property var" with int type, that is, assign it zero, then call gc() and Unknown memory under this variable will be released

Upvotes: 0

Stephen Quan
Stephen Quan

Reputation: 26289

Below is an example of how you may redesign:

  • instead of calling createComponent() it uses a StackView for dynamically creating and destroying Pages with push/pop. Similar approaches could be done with Repeater/ListModel and an appropriate delegate
  • there is deliberately no call to delete - we expect the JSEngine to take care of dynamic destruction and/or recycling of our garbaged objects
  • and, if we must, we can call gc() but, I put it in a Qt.callLater() to ensure that the Page has fully been popped of the stack and had time to destroy
import QtQuick
import QtQuick.Controls
Page {
    property int count: 0
    StackView {
        id: stackView
        anchors.fill: parent
        initialItem: "MainPage.qml"
        onDepthChanged: Qt.callLater(callGC)
    }
    function callGC() {
        gc();
        ++count;
    }
    footer: Frame { Text { text: "gc count %1".arg(count) } }
}

// MainPage.qml
import QtQuick
import QtQuick.Controls
Page {
    header: Frame { Text { text: "Main.qml" } }
    Button {
        anchors.centerIn: parent
        text: "open window1"
        onClicked: {
            stackView.push("SecondPage.qml")
        }
    }
}

// SecondPage.qml
import QtQuick
import QtQuick.Controls

Page {
    header: Frame { Text { text: "SecondPage.qml" } }
    property var name: [ ]
    Button {
        anchors.centerIn: parent
        text: qsTr("destroy window1")
        onClicked: stackView.pop();
    }
    Component.onCompleted: {
        //for (let i=1; i < 1000000; i++) {
        for (let i=1; i < 1000; i++) {
            name.push();
        }
    }
}

You can Try it Online!

Upvotes: 0

Related Questions