Details
-
Bug
-
Resolution: Done
-
P1: Critical
-
5.6.3, 5.9.9, 5.12.6, 5.14.0, 5.14.1, 5.15.0 Beta2
-
WIndows 10 Pro, Intel Xeon E5-1650 v3 and AMD Ryzen 3900X, 32GB RAM, Qt Creator 4.11.2, Qt 5.6.3, Qt 5.9.6, Qt 5.12.6, Qt 5.14.0, Qt 5.14.1, Qt 5.15 beta 2
-
-
6de0287d7c3aa4251fe6eb4f970d73ce11cf07fc (qt/qtdeclarative/dev) 5d6c671232ca466a929cc23ee8ae92de2ce9ca8d (qt/qtdeclarative/5.15)
Description
QML components having a StateMachine with an “onTriggered” signal handler leak memory when destroyed.
The attached QML file has a Repeater with Rectangles containing a StateMachine. One of the States has a “trigger” signal handler in a SignalTransition. If the Repeater is repopulated rapidly, the memory usage for the process (measured using Windows Task Manager) grows continually. If the “onTriggered” signal handler is commented out, memory usage does not grow.
To reproduce:
- Build and run the attached project
- Open Windows Task Manager to the “Processes” tab and find the “QML Scene Viewer” (or "QmlScene", depends on Qt version)
Observe that under the Memory column, the memory usage grows by about 100 MB a minute
- Close the app window
- Edit the DsmMemoeryLeak.qml file to comment-out line 44: "onTriggered: root.canceled()"
- Build and run the project again
- On the Task Manager “Processes” tab, find the “QML Scene Viewer”
Observe that under the Memory column, memory usage stabilizes around 65-105MB (depends on Qt version) and does not grow.
Here's the content of the file:
// DsmMemoryLeak.qml import QtQuick 2.6 import QtQuick.Window 2.2 import QtQml.StateMachine 1.0 as DSM Window { visible: true width: 600 height: 80 title: qsTr("DSM Memory Leak") Row { id: row property int count: 1 anchors.verticalCenter: parent.verticalCenter spacing: 1 Repeater { model: row.count delegate: Rectangle { id: root signal bumped() signal canceled() width: 9; height: 20 color: "green" DSM.StateMachine { initialState: s1 running: true DSM.State { id: s1 DSM.SignalTransition { targetState: s3 signal: root.bumped } } DSM.State { id: s2 DSM.SignalTransition { targetState: s1; signal: root.bumped // comment out line below to stop leak onTriggered: root.canceled() } } DSM.State { id: s3 DSM.TimeoutTransition { targetState: s1 timeout: 500 } } } } } } Timer { interval: 1 running: true repeat: true onTriggered: row.count = (row.count == 60) ? 0 : 60 } }