Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. QObjects are being deleted by a Loader
Forum Updated to NodeBB v4.3 + New Features

QObjects are being deleted by a Loader

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
qt6loadermemorymanagemen
4 Posts 2 Posters 547 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    malocascio
    wrote on last edited by
    #1

    I noticed some odd behavior in my application, so I stripped it down to a very small test app to see what's going on. An example using both C++ and PySide6 can be found here. The organization of the app isn't the best because it's been ripped apart, so forgive some oddities.

    The QML side of the app is really just a Loader. The source of the Loader is bound to a property from the C++ or Python side. I then have a QTimer set up to toggle the source between two different QML files. Depending on several factors, the Loader will do this for several iterations, but then eventually fail to load (it sometimes takes hundreds or thousands of iterations, which is why the timer has 10 ms iterations... it's hard to look at it flickering).

    I have dug into this, and I found that my QObjects are being deleted when I don't expect them to. This is easier to see in the C++ version. My root context object allocates (using new) two QmlFileWrapper objects (which are QObjects):

    auto h = new QmlFileWrapper("Home.qml");
    auto o = new QmlFileWrapper("Other.qml");
    

    My expectation, since I didn't set a parent for either object, is that those two objects will never be deleted unless I explicitly do so (or the application ends). The source of my Loader is bound to a property that gets a member of the QmlFileWrapper, so when that object eventually gets deleted, the Loader's source can no longer find it to get the QML file path.

    I added a connection to the object's onDestroy to prove that out, and sure enough, eventually one of those two objects gets deleted. If I change it so that those two QmlFileWrapper objects are children of another object with the lifetime of the whole application, it runs indefinitely:

    auto h = new QmlFileWrapper("Home.qml", this);
    auto o = new QmlFileWrapper("Other.qml", this);
    

    So, there are several learning opportunities here:

    1. If I new a QObject and do not specify a parent, is it reasonable to think that it will never be deleted until I do it explicitly?
    2. When the Loader changes its source, does it destroy the QML object that had previously been loaded?
    3. One thing to note is that the QML objects that get loaded contain a reference to one of those two QmlFileWrapper objects. It's obviously not the case that, when the Loader changes its source, the QmlFileWrapper gets immediately deleted, because this thing runs for hundreds/thousands of iterations before failing. However, it seems like the javascript memory manager does eventually decide to clean them up, because I have seen some QV4::MemoryManager references while digging around in the stack traces.

    Can anyone help me understand what's happening here? This happens in Qt 6.2.1 and 6.5.1. Thanks!

    Axel SpoerlA 1 Reply Last reply
    0
    • M malocascio

      I noticed some odd behavior in my application, so I stripped it down to a very small test app to see what's going on. An example using both C++ and PySide6 can be found here. The organization of the app isn't the best because it's been ripped apart, so forgive some oddities.

      The QML side of the app is really just a Loader. The source of the Loader is bound to a property from the C++ or Python side. I then have a QTimer set up to toggle the source between two different QML files. Depending on several factors, the Loader will do this for several iterations, but then eventually fail to load (it sometimes takes hundreds or thousands of iterations, which is why the timer has 10 ms iterations... it's hard to look at it flickering).

      I have dug into this, and I found that my QObjects are being deleted when I don't expect them to. This is easier to see in the C++ version. My root context object allocates (using new) two QmlFileWrapper objects (which are QObjects):

      auto h = new QmlFileWrapper("Home.qml");
      auto o = new QmlFileWrapper("Other.qml");
      

      My expectation, since I didn't set a parent for either object, is that those two objects will never be deleted unless I explicitly do so (or the application ends). The source of my Loader is bound to a property that gets a member of the QmlFileWrapper, so when that object eventually gets deleted, the Loader's source can no longer find it to get the QML file path.

      I added a connection to the object's onDestroy to prove that out, and sure enough, eventually one of those two objects gets deleted. If I change it so that those two QmlFileWrapper objects are children of another object with the lifetime of the whole application, it runs indefinitely:

      auto h = new QmlFileWrapper("Home.qml", this);
      auto o = new QmlFileWrapper("Other.qml", this);
      

      So, there are several learning opportunities here:

      1. If I new a QObject and do not specify a parent, is it reasonable to think that it will never be deleted until I do it explicitly?
      2. When the Loader changes its source, does it destroy the QML object that had previously been loaded?
      3. One thing to note is that the QML objects that get loaded contain a reference to one of those two QmlFileWrapper objects. It's obviously not the case that, when the Loader changes its source, the QmlFileWrapper gets immediately deleted, because this thing runs for hundreds/thousands of iterations before failing. However, it seems like the javascript memory manager does eventually decide to clean them up, because I have seen some QV4::MemoryManager references while digging around in the stack traces.

      Can anyone help me understand what's happening here? This happens in Qt 6.2.1 and 6.5.1. Thanks!

      Axel SpoerlA Online
      Axel SpoerlA Online
      Axel Spoerl
      Moderators
      wrote on last edited by
      #2

      @malocascio
      Generally, there is no automagic deletion of a QObject.
      Best to set a breakpoint in the destructor of QmlFileWrapper and check the stack trace for the caller.

      Software Engineer
      The Qt Company, Oslo

      M 1 Reply Last reply
      0
      • Axel SpoerlA Axel Spoerl

        @malocascio
        Generally, there is no automagic deletion of a QObject.
        Best to set a breakpoint in the destructor of QmlFileWrapper and check the stack trace for the caller.

        M Offline
        M Offline
        malocascio
        wrote on last edited by
        #3

        @Axel-Spoerl said in QObjects are being deleted by a Loader:

        @malocascio
        Generally, there is no automagic deletion of a QObject.
        Best to set a breakpoint in the destructor of QmlFileWrapper and check the stack trace for the caller.

        Hi Axel,

        Thanks for getting back to me! I dug in deep and finally found out what the problem was. I was not aware of the concept of ownership for QML objects. While I was creating my wrapper objects in Python or C++, I wasn't giving them parents. So it seems like when I set a property in the loaded QML, the javascript engine was taking ownership of the wrappers that didn't have a parent. After changing the Loader's source several times, the javascript engine did some cleanup and freed the wrapper objects.

        This makes sense, and the fix was simply to set a parent for my wrapper objects in Python or C++. Then the javascript engine doesn't try to clean them up. This was a valuable lesson to learn!

        Thanks!

        Axel SpoerlA 1 Reply Last reply
        3
        • M malocascio

          @Axel-Spoerl said in QObjects are being deleted by a Loader:

          @malocascio
          Generally, there is no automagic deletion of a QObject.
          Best to set a breakpoint in the destructor of QmlFileWrapper and check the stack trace for the caller.

          Hi Axel,

          Thanks for getting back to me! I dug in deep and finally found out what the problem was. I was not aware of the concept of ownership for QML objects. While I was creating my wrapper objects in Python or C++, I wasn't giving them parents. So it seems like when I set a property in the loaded QML, the javascript engine was taking ownership of the wrappers that didn't have a parent. After changing the Loader's source several times, the javascript engine did some cleanup and freed the wrapper objects.

          This makes sense, and the fix was simply to set a parent for my wrapper objects in Python or C++. Then the javascript engine doesn't try to clean them up. This was a valuable lesson to learn!

          Thanks!

          Axel SpoerlA Online
          Axel SpoerlA Online
          Axel Spoerl
          Moderators
          wrote on last edited by
          #4

          @malocascio
          Good morning,
          thanks for sharing the solution! You found it yourself, I wasn't of much help here...

          Software Engineer
          The Qt Company, Oslo

          1 Reply Last reply
          0

          • Login

          • Login or register to search.
          • First post
            Last post
          0
          • Categories
          • Recent
          • Tags
          • Popular
          • Users
          • Groups
          • Search
          • Get Qt Extensions
          • Unsolved