2016-11-18 7 views
0

Не бойтесь! Это не производственный код. Это просто узнать о QML! Я не ищу «вы не будете делать что-то подобное - сделайте это так». Я больше заинтересован в внутренностей QMLGC аварии QML-приложение

Рассмотрим следующий QML-код

import QtQuick 2.4 
import QtQuick.Window 2.0 

Window { 
    id: root 
    width: 800 
    height: 600 
    visible: true 
    GridView { 
     width: 800 
     height: 200 
     model: 4000 
     flow: GridView.FlowTopToBottom 

     delegate: Rectangle { 
      id: myDelegate 
      width: 100 
      height: 100 
      border.width: 1 
      Column { 
       anchors.fill: parent 
       Text { 
        text: index 
        height: 20 
        width: parent.width 
       } 
       Item { 
        id: frame0 
        height: 20 
        width: parent.width 
       } 
       Item { 
        id: frame1 
        height: 20 
        width: parent.width 
       } 
      } 

      Component.onCompleted: { 
       // if (index % 100 === 0) gc() 
       frame0.children = [myComp.createObject(myDelegate)] 
       frame1.children = [myComp.createObject(null)] 
       frame0.children[0].text = 'QML ' + index 

       frame1.children[0].text = 'JS ' + index 
      } 
     } 

     Component { 
      id: myComp 
      Text { 
       anchors.centerIn: parent 
       Component.onDestruction: console.log('Destroy ' + text) 
      } 
     } 
    } 
} 

Это иллюстрирует в некоторой степени MemoryManagement из QML при использовании динамического ObjectCreation (JS). У меня есть ListView, который создает несколько делегатов и позволяет мне просматривать их, создавая новые по требованию.

Уловка: когда создается новый делегат, он использует создание динамического объекта JavaScript для создания двух экземпляров текстового объекта.

Один из них является родительским для делегата, а другой - от null, и поэтому его жизнь определяется JS-Engine. Это должен быть сбор мусора, когда нет указателя слева, указывая на него.

Для начала отправьте оба из них в frame (Item), чтобы отобразить (установить визуальный родитель). Как делегат, эти рамки уничтожаются. Это, как и ожидалось, уничтожит динамически созданный объект, который также имеет делегат как родительский. Другой (должен быть) оставлен для Мусороуборочного завода для выполнения его работы.

И здесь это не удается - иногда приложение выходит из строя, прежде чем GC запускается, иногда он падает, в то время как GC пытается выполнить свою работу.

Хотя это не рекомендуется документацией, оно действительно помогает вызвать GC manualy (активировать строку, прокомментированную в Component.onCompleted).

Итак, мне кажется, GC переоценивает свои способности и решает нанести удар, когда уже будет поздно.

Что может быть причиной этого? Есть ли способ сказать GC быть mor proactive?

Опять: Я не намерен использовать динамическое создание объектов с .createObject(null) в моем коде. Это чистое любопытство.

+0

Вы пытались сделать это, установив вновь созданный объект в обычное свойство? Мое предположение было бы в том, что свойство 'children' отличается от другого, поскольку оно имеет другую семантику. –

+0

Не имеет значения, ref counting должен работать в любом случае. – dtech

+0

@ddriver Мое предположение заключается в том, что движок QML ожидает, что объект будет находиться под правами сценария, поскольку он не имеет родителя, но на самом деле находится под лицензией C++, т. Е. Удаляется с помощью 'children'. Следовательно, рекомендуется попробовать с единственным свойством объекта, чтобы проверить, является ли это обычным «без родительского элемента, а также не помечено для владельца C++, но удалено в C++». –

ответ

1

В чем может быть причина этого? Есть ли способ сообщить GC, что он mor proactive?

Причиной этого является реализация buggy qtquick object lifetime. На данный момент это не похоже на вещь JS, а на то, что нужно. Очевидно, что doesn't abide to its own alleged rules - например, он удалит объект с родителем во время его использования, что приведет к жесткому сбою. Вы не можете ожидать, что подсчет ссылок также будет работать. Такое поведение может возникать в ряде сценариев, которые используют динамизм, как правило, не проявляются в тривиальных и статических сценариях.

Решение, как уже указывалось в связанном вопросе, заключается в использовании управления временем жизни вручную.Используйте набор новых функций для создания и удаления объектов.

  • для создания, вы должны передать объект в сторону C++, чтобы вызвать QQmlEngine::setObjectOwnership(ojb, QQmlEngine::CppOwnership); на нем, это в основном говорит QtQuick «даже не пытайся», к счастью, по крайней мере, это работает, как предполагается
  • для уничтожения, необходимо передать объект на стороне C++ для того, чтобы позвонить obj->deleteLater();

для меня это делает трюк, я больше не получаю аварии без видимых причин. Используйте индивидуальное управление жизненным циклом и держитесь подальше от функций запаса. Это дает вам гарантии, что объект останется в живых до тех пор, пока он вам понадобится, но также и то, что он не пройдет мимо точки, где вы хотите, и это еще одна проблема, хотя и не такая уж серьезная. Конечно, это исключает фактор удобства использования JS, так как вам приходится отказаться от автоматического управления жизненным циклом и быть немного более прилежным и явным с вашим собственным кодом, но вы не можете с этим поделать. Несмотря на то, что ошибка была зарегистрирована почти год назад и считалась критической, не было сделано никакой работы об этом. Таким образом, я предполагаю, что как критический, поскольку это может быть по своей строгости, это больше похоже на самый низкий приоритет, когда дело доходит до нахождения его причины и его исправления.

+0

Отчет об ошибке, с которым вы связаны, кажется, предполагает, что родительский item также является родителем QObject. То есть он проверяет идентификатор/ссылку QML 'parent', который является родительским элементом, а не родителем QObject. Возможно, в рассматриваемых элементах нет родителя QObject? –

+0

@ KevinKrammer - это просто для примера. В моем производственном коде объекты, которые удаляются, являются невидимыми типами 'QObject', которые связывают правильное родительское отношение с QML. Они удаляются с допустимым родителем и с несколькими ссылками на них. Это определенно нарушено. – dtech

+0

ОК, но об этом не было в отчете об ошибке. Он проверяется только на свойство «parent», которое является родительским элементом, а не родителем QObject. –

 Смежные вопросы

  • Нет связанных вопросов^_^