Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-117634

QML Garbage Collection takes excessive time

    XMLWordPrintable

Details

    • Linux/Yocto

    Description

      Our UI application currently targeting with Qt 5.15.x is experiencing periodical stutters of ~900ms every few minutes. From the garbage collection debug logging we can see that this stutter is due to the garbage collection.


      Example of GC logging:

      Aug 02 13:04:59 ========== GC ==========|:0|GUI
      Aug 02 13:04:59 Allocated 82446336 bytes in 1276 chunks|:0|GUI
      Aug 02 13:04:59 Fragmented memory before GC 111168|:0|GUI
      Aug 02 13:04:59 Slot map for Block allocator:|:0|GUI
      Aug 02 13:04:59 number of entries in slot 0 : 0|:0|GUI
      Aug 02 13:04:59 number of entries in slot 1 : 0|:0|GUI
      Aug 02 13:04:59 number of entries in slot 2 : 0|:0|GUI
      Aug 02 13:04:59 number of entries in slot 3 : 0|:0|GUI
      Aug 02 13:04:59 number of entries in slot 4 : 0|:0|GUI
      Aug 02 13:04:59 number of entries in slot 5 : 0|:0|GUI
      Aug 02 13:04:59 number of entries in slot 6 : 0|:0|GUI
      Aug 02 13:04:59 number of entries in slot 7 : 0|:0|GUI
      Aug 02 13:04:59 total mem in bins 0|:0|GUI
      Aug 02 13:04:59 Slot map for InternalClass allocator:|:0|GUI
      Aug 02 13:04:59 number of entries in slot 0 : 0|:0|GUI
      Aug 02 13:04:59 number of entries in slot 1 : 0|:0|GUI
      Aug 02 13:04:59 number of entries in slot 2 : 0|:0|GUI
      Aug 02 13:04:59 number of entries in slot 3 : 0|:0|GUI
      Aug 02 13:04:59 number of entries in slot 4 : 75|:0|GUI
      Aug 02 13:04:59 number of entries in slot 5 : 0|:0|GUI
      Aug 02 13:04:59 number of entries in slot 6 : 51|:0|GUI
      Aug 02 13:04:59 number of entries in slot 7 : 33|:0|GUI
      Aug 02 13:04:59 total mem in bins 76928|:0|GUI
      Aug 02 13:05:00 triggered by unmanaged heap:|:0|GUI
      Aug 02 13:05:00 old unmanaged heap size: 4194349|:0|GUI
      Aug 02 13:05:00 new unmanaged heap: 2044979|:0|GUI
      Aug 02 13:05:00 unmanaged heap limit: 4194304|:0|GUI
      Aug 02 13:05:00 Slot map for Block allocator:|:0|GUI
      Aug 02 13:05:00 number of entries in slot 0 : 0|:0|GUI
      Aug 02 13:05:00 number of entries in slot 1 : 8887|:0|GUI
      Aug 02 13:05:00 number of entries in slot 2 : 7378|:0|GUI
      Aug 02 13:05:00 number of entries in slot 3 : 3056|:0|GUI
      Aug 02 13:05:00 number of entries in slot 4 : 1742|:0|GUI
      Aug 02 13:05:00 number of entries in slot 5 : 3253|:0|GUI
      Aug 02 13:05:00 number of entries in slot 6 : 2353|:0|GUI
      Aug 02 13:05:00 number of entries in slot 7 : 11122|:0|GUI
      Aug 02 13:05:00 total mem in bins 13561632|:0|GUI
      Aug 02 13:05:00 Slot map for InternalClasss allocator:|:0|GUI
      Aug 02 13:05:00 number of entries in slot 0 : 0|:0|GUI
      Aug 02 13:05:00 number of entries in slot 1 : 0|:0|GUI
      Aug 02 13:05:00 number of entries in slot 2 : 60|:0|GUI
      Aug 02 13:05:00 number of entries in slot 3 : 0|:0|GUI
      Aug 02 13:05:00 number of entries in slot 4 : 76|:0|GUI
      Aug 02 13:05:00 number of entries in slot 5 : 0|:0|GUI
      Aug 02 13:05:00 number of entries in slot 6 : 52|:0|GUI
      Aug 02 13:05:00 number of entries in slot 7 : 37|:0|GUI
      Aug 02 13:05:00 total mem in bins 82432|:0|GUI
      Aug 02 13:05:00 Marked object in 732049 us.|:0|GUI
      Aug 02 13:05:00 1312570 objects marked|:0|GUI
      Aug 02 13:05:00 Sweeped object in 216253 us.|:0|GUI
      Aug 02 13:05:00 Used memory before GC: 82335168|:0|GUI
      Aug 02 13:05:00 Used memory after GC: 62544608|:0|GUI
      Aug 02 13:05:00 Freed up bytes : 19790560|:0|GUI
      Aug 02 13:05:00 Freed up chunks : 97|:0|GUI
      Aug 02 13:05:00 ======== End GC ========|:0|GUI

      Simple example application with which I can see similar behavior:

      import QtQuick 2.15
      import QtQuick.Window 2.15
      
      Window {
          id: window
          width: 640
          height: 480
          visible: true
          title: qsTr("Rectangles")
          readonly property int staticRectCount: 100000
          readonly property int dynamicRectCount: 100
          
          // Static, invisible objects consuming memory from the JS heap.
          Repeater {
              model: staticRectCount
              Rectangle {
                  visible: false
                  x: Math.random() * window.width
                  y: Math.random() * window.height
                  width: Math.random() * 20
                  height: Math.random() * 20
                  color: Qt.rgba(Math.random(),Math.random(),Math.random(), 1)
              }
          }    
      
          // Dynamic, visible objects with properties changing on interval, presumably
          // causing dynamic memory allocations and frees.
          Repeater {
              id: changingRects
              model: dynamicRectCount
              Rectangle {
                  visible: true
                  x: Math.random() * window.width
                  y: Math.random() * window.height
                  width: Math.random() * 20
                  height: Math.random() * 20
                  color: Qt.rgba(Math.random(),Math.random(),Math.random(), 1)
              }
          }
          Timer {
              interval: 2000; running: true; repeat: true
              onTriggered: changingRects.model = dynamicRectCount + Math.random() * 20
          }    
      
          // Rectangle moving smoothly accross the screen.
          // Updates to this should stay smooth over any garbage collection.
          //
          // Note: not using animation, as I've understood that those could happen in
          // separate render thread instead of the main thread
          Rectangle {
              id: movingRect
              visible: true
              x: 0
              y: 0
              width: 100
              height: 100
              color: "red"
          }
          Timer {
              interval: 40; running: true; repeat: true
              onTriggered: {
                  movingRect.x++;
                  if (movingRect.x > window.width) {
                      movingRect.x = 0;
                  }
              }
          }
      } 

      Not sure how representative the above is to what our application is actualy doing.
      However, in a quick test the above would result in the GC running every 21 minutes and taking ~900ms:

      qt.qml.gc.allocatorStats: Marked object in 516237 us.
      qt.qml.gc.allocatorStats:     302094 objects marked
      qt.qml.gc.allocatorStats: Sweeped object in 424215 us.
      qt.qml.gc.allocatorStats: Used memory before GC: 32198560
      qt.qml.gc.allocatorStats: Used memory after GC: 16114400
      qt.qml.gc.allocatorStats: Freed up bytes      : 16084160
      qt.qml.gc.allocatorStats: Freed up chunks     : 216

      Attached a full project, which I used in my test.

      Attachments

        1. gc-test.tar
          13 kB
          Lasse Lopperi

        Issue Links

          No reviews matched the request. Check your Options in the drop-down menu of this sections header.

          Activity

            People

              fabiankosmale Fabian Kosmale
              lasse.lopperi Lasse Lopperi
              Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Gerrit Reviews

                  There are no open Gerrit changes