Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QML memory increase continuously



  • Hi, all.
    I am dealing with QML memory increasement all this week. It can be easily reproduced with simple code below.(Qt 5.12.9, embedded linux system)

    informations:

    1. I use “cat /proc/.../status | grep "VmSize|VmRSS" to observe memory increase, it grows fast. Also I realize that Linux allocates memory more than app needs, so I use another app to allocate all left memory to make the data more trusting. Sadly, it still grows.

    2. gc() function is called, but only a few memory is freed.

    3. Valgrind is also used, the result is below. The definitely and indirectly lost does not match the real consumption. I doubt the "still reachable memory" is the main reason.

    4. In souce code, I found the QQmlContextData seems not released. It is maintained by the parent context. (QQmlObjectCreator::create)

    context = new QQmlContextData;
    context->isInternal = true;
    context->imports = compilationUnit->typeNameCache;
    context->initFromTypeCompilationUnit(compilationUnit, subComponentIndex);
    context->setParent(parentContext);
    

    My question:

    1. When will QQmlContextData release? Why its life circle is not same with the QObject created(the component)? (when destroy() is called, it only call deleteLater(), then delete self pointer. the QObjects only contains self with QQmlData(in declativeData))

    2. Do you have suggestions about the memory control? The memory increasement is obviously not acceptable on embedded system.

    3. Why QML uses so large memories? I guess the memory is in two parts: C++/Js Engine. the gc() function only release a little, not all, even destroy() called.

    Valgrind test:

    ==31907== 120 bytes in 15 blocks are definitely lost in loss record 1,308 of 1,988
    ==31907==    at 0x4841D20: operator new[](unsigned long) (vg_replace_malloc.c:433)
    ==31907==    by 0x590C647: QStringHash<QPair<int, QQmlPropertyData*> >::linkAndReserve(QStringHash<QPair<int, QQmlPropertyData*> > const&, int) (in /usr/lib/libQt5Qml.so.5.12.9)
    
    ==31907== 1,701 (512 direct, 1,189 indirect) bytes in 1 blocks are definitely lost in loss record 1,847 of 1,988
    ==31907==    at 0x48434E8: realloc (vg_replace_malloc.c:836)
    ==31907==    by 0x71344E7: FcPatternObjectInsertElt (in /usr/lib/libfontconfig.so.1.9.2)
    
    
    ==31907== 8,152 bytes in 1,019 blocks are definitely lost in loss record 1,921 of 1,988
    ==31907==    at 0x4841D20: operator new[](unsigned long) (vg_replace_malloc.c:433)
    ==31907==    by 0x58E29BF: QQmlContextData::initFromTypeCompilationUnit(QQmlRefPointer<QV4::CompiledData::CompilationUnit> const&, int) (in /usr/lib/libQt5Qml.so.5.12.9)
    
    ==31907== 189,152 bytes in 1,028 blocks are still reachable in loss record 1,987 of 1,988
    ==31907==    at 0x484166C: operator new(unsigned long) (vg_replace_malloc.c:344)
    ==31907==    by 0x592E87F: QQmlObjectCreator::create(int, QObject*, QQmlInstantiationInterrupt*) (in /usr/lib/libQt5Qml.so.5.12.9)
    ==31907== 
    ==31907== 469,602 bytes in 175 blocks are still reachable in loss record 1,988 of 1,988
    ==31907==    at 0x4841054: malloc (vg_replace_malloc.c:309)
    ==31907==    by 0x7175EF3: ft_mem_qalloc (in /usr/lib/libfreetype.so.6.11.4)
    ==31907== 
    ==31907== LEAK SUMMARY:
    ==31907==    definitely lost: 8,784 bytes in 1,035 blocks
    ==31907==    indirectly lost: 1,189 bytes in 43 blocks
    ==31907==      possibly lost: 2,840 bytes in 18 blocks
    ==31907==    still reachable: 3,185,715 bytes in 19,864 blocks
    ==31907==                       of which reachable via heuristic:
    ==31907==                         newarray           : 74,704 bytes in 44 blocks
    ==31907==                         multipleinheritance: 136 bytes in 2 blocks
    ==31907==         suppressed: 0 bytes in 0 blocks
    
    

    Souce code:

    import QtQuick 2.12
    import QtQuick.Controls 2.12
    import QtQuick.Layouts 1.12
    import "qrc:/res/qml"
    
    import QtQuick.Window 2.2
    
    ApplicationWindow { 
        id: window
        width: 960
        height: 480
        title: "Buttons"
        visible: true 
    
        ScrollView {
            width: 960
            height : 240
            y: 120
    
                Column {
                    id: contentView
                    width: parent.width
                    leftPadding: 10
                    spacing: 5
    				
                    property var objArr : []
                    
                    
                    Button {
                        id: btnCreate
                        width: 300
                        height : 50
                        text : qsTr("create items")
    
                        onClicked: {
                            for(var i =0 ; i < 20000; i++) {
                                var obj = itemView.createObject(container);
                                contentView.objArr.push(obj);
                            }
    
                            console.log("create " + i + " views");
                        }
                    }
    
                    Button {
                        id: btnClean
                        width: 300
                        height : 50
                        text : qsTr("clear items")
                        
    
                        onClicked: {
                            for(var i =0 ; i < contentView.objArr.length; i++) {
                               contentView.objArr[i].destroy();
                            }
    
                            console.log("release all " + contentView.objArr.length + " views");
                            contentView.objArr.splice(0, contentView.objArr.length);  
    
                        }
                    }
    
                    Button {
                        id: btnGC
                        width: 300
                        height : 50
                        text : qsTr("GC")
                        
    
                        onClicked: {
                            gc();
                            console.log("gc called");
                        }
                    }
    
                    Column {
                        id: container
                        spacing: 5
                    }
                }
        }
    
        Component {
            id: itemView
            Text {
                text: "I am text"
                color: "red"
                Component.onCompleted: {
    			    console.log(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> item is created");
    		    }
                 Component.onDestruction: {
    			    console.log(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> item is destroyed\n");
    			}
            }
        }
    
    }
    
    

    the C++ code below:

    int main(int argc, char *argv[])
    {
    
        QGuiApplication app(argc, argv);
    
        QQmlApplicationEngine engine;
        engine.load(QUrl(QStringLiteral("./res/qml/MainPage.qml")));
        
        int res = app.exec();
        return res;
    }
    


  • @FeelFree said in QML memory increase continuously:

    ory is in two parts: C++/Js Engine. the gc() function only releas

    PS: the context is stored in QQmlData with property "context", but not released in void QQmlData::destroyed(QObject *object), also not released QQmlData::~QQmlData.


Log in to reply