воскресенье, 26 декабря 2010 г.

Qyoto and GC issues

Сегодня пол дня слушал песню Amy Winehouse "You Know I'm No Good" и долбался с одной проблемой в Qyoto (а их по-видимому там не мало). До причины я все-таки докопался, но хотел описать все завтра, так как сейчас уже довольно поздно, но неожиданно для себя в одном из источников по Qyoto, с которым я работал, в одном из примеров обнаружил метку, лежащую на форме с цитатой из этой песни. Это судьба, это словно зуб Гоя (Серьезный Человек), подумал я и решел все-таки написать пост сегодня.
А проблема следующая: У меня есть два идентичных куска кода на C# (Qyoto) и на C++ (Qt 4.7), создающие QMainWindow с QTreeView, лежащем на нем. Этому TreeView скармливается QStandardItemModel содержащая в себе некоторые QStandardItem'ы. В случае Qt все работает хорошо, а вот в Qyoto item'ы на мгновение появляются, а потом почему-то исчезают.
В результате выяснилось, что item'ы на которые нет ссылок из managed кода просто собираются GC, не смотря на то, что они были добавлены в модель и по идее ссылки на них должны храниться в этой самой QStandardItemModel!!! Такова уж специфика работы Smoke, будем иметь это ввиду.
Выяснить это удалось при помощи слабых ссылок. Ниже приведен код на примере которого можно убедиться в верности предположения:

using System;
using Qyoto;
using System.Collections.Generic;
namespace QyotoDrv
{
  public class MainWindow : QMainWindow
  {
    Ui.MainWindow _ui;
    
    QStandardItem it1; //menu item referred from MainWindow

    WeakReference _wr1; //weak reference to it1
    WeakReference _wr2; //weak reference to it2
    
    const string SlotShowWR = "slot_ShowWR()";
    
    public MainWindow ()
    {
      _ui = new Ui.MainWindow(); 
      _ui.SetupUi(this);  
      
      SetModel();
    }
    
    void SetModel()
    {
      var model = new QStandardItemModel(_ui.treeView);
      
      it1 = new QStandardItem("Hello, World!");
      model.AppendRow(it1);

      //the following menu item is not referred from MainWindow and will be collected by GC,
      //in spite of being added to the model!!!
      QStandardItem it2 = new QStandardItem("Good bye, World!");
      model.AppendRow(it2);
      
      _ui.treeView.SetModel(model);

      //set weak references pointing to the corresponding menu items
      _wr1 = new WeakReference(it1);
      _wr2 = new WeakReference(it2);
      
            
      QMenu file = MenuBar().AddMenu("Click me!");
      
      QAction showWR = new QAction("Show Weak References", this);
      file.AddAction(showWR);
      Connect(showWR, SIGNAL("triggered()"), this, SLOT(SlotShowWR));
    }
    
    [Q_SLOT(SlotShowWR)]
    void ShowWeakReference()
    {
      //after the main window will be shown wait a fiew seconds until the second item has disappeared
      Console.WriteLine("wr1.IsAlive={0}", _wr1.IsAlive); //is alive
      Console.WriteLine("wr2.IsAlive={0}", _wr2.IsAlive); //is not alive!
    }
  } 
}


* This source code was highlighted with Source Code Highlighter.


Запустите приложение. После появления главного окна дождитесь пока второй item не исчезнет, после чего щелкните на пункт меню "Click me! > Show Weak References" и посмотрите на консоль.
Комменты на английском сделаны для возможных англоязычных посетителей, чтоб хоть чем-то помочь им, слишком уж мало материала в сети на тему Qyoto.

Комментариев нет:

Отправить комментарий