Уведомления

Группа в Telegram: @pythonsu
  • Начало
  • » GUI
  • » Python 2.7.13 + QtGUI из комплекта Qt 4.8.6/4.8.7 в любых ОС = Segmentation Fault [RSS Feed]

#1 Сен. 1, 2017 14:15:37

Vady
Зарегистрирован: 2015-05-30
Сообщения: 70
Репутация: +  0  -
Профиль   Отправить e-mail  

Python 2.7.13 + QtGUI из комплекта Qt 4.8.6/4.8.7 в любых ОС = Segmentation Fault

py.user.next
Набираешь “10000 c” и он проходит 10000 раз без остановки, а потом останавливается.
В моей ситуации сегфолт происходит не ровно в одном и том же месте. Может случиться не только после 10000 раз, но и 10001, 10022, 14522 и даже 456789 раз. Нет закономерности…

Офлайн

#2 Сен. 1, 2017 23:36:02

Vady
Зарегистрирован: 2015-05-30
Сообщения: 70
Репутация: +  0  -
Профиль   Отправить e-mail  

Python 2.7.13 + QtGUI из комплекта Qt 4.8.6/4.8.7 в любых ОС = Segmentation Fault

С закомментированным notify() нашел сегфолты в двух местах кода. Об одном из них раскажу:

     def setupDirtyCatherForObject(self, obj, exclude):
        print obj
        if obj in exclude:
            return
        print 'library/DialogBase.py 2-30_2_1'
        print obj.children()
        print 'library/DialogBase.py 2-30_2_2'
        for child in obj.children():
            print 'library/DialogBase.py 2-30_3'
            if isinstance(child, QtGui.QLabel) or child in exclude:
                pass
            elif isinstance(child, CDateEdit):
                self.connect(child, SIGNAL('dateChanged(QDate)'), self.on_dateEditChanged)
            elif isinstance(child, QtGui.QLineEdit):
                self.connect(child, SIGNAL('textChanged(QString)'), self.on_lineEditChanged)
            elif isinstance(child, QtGui.QTextEdit):
                self.connect(child, SIGNAL('textChanged()'), self.on_textEditChanged)
            elif isinstance(child, QtGui.QDateEdit):
                self.connect(child, SIGNAL('dateChanged(QDate)'), self.on_dateEditChanged)
            elif isinstance(child, QtGui.QComboBox):
                self.connect(child, SIGNAL('currentIndexChanged(int)'), self.on_comboBoxChanged)
            elif isinstance(child, QtGui.QCheckBox):
                self.connect(child, SIGNAL('stateChanged(int)'), self.on_checkBoxChanged)
            elif isinstance(child, QtGui.QSpinBox):
                self.connect(child, SIGNAL('valueChanged(int)'), self.on_spinBoxChanged)
            elif isinstance(child, QAbstractItemModel):
                self.connect(child, SIGNAL('dataChanged(QModelIndex, QModelIndex)'), self.on_abstractdataModelDataChanged)
                self.connect(child, SIGNAL('rowsInserted(QModelIndex, int, int)'), self.on_abstractdataModelDataChanged)
                self.connect(child, SIGNAL('rowsMoved(QModelIndex, int, int, QModelIndex, int)'), self.on_abstractdataModelDataChanged)
                self.connect(child, SIGNAL('rowsRemoved(QModelIndex, int, int)'), self.on_abstractdataModelDataChanged)
            else:
                self.setupDirtyCatherForObject(child, exclude)
Сегфолт происходит на том участке кода:
         print 'library/DialogBase.py 2-30_2_1'
        print obj.children()
        print 'library/DialogBase.py 2-30_2_2'
До сегфолта увидел только первый принт из трех. Есть варианты решения проблемы?

Офлайн

#3 Сен. 2, 2017 11:47:46

vic57
Зарегистрирован: 2015-07-07
Сообщения: 893
Репутация: +  126  -
Профиль   Отправить e-mail  

Python 2.7.13 + QtGUI из комплекта Qt 4.8.6/4.8.7 в любых ОС = Segmentation Fault

Vady
решил перейти на более современную линуксовую ОС.
если стабильно падает ,как вариант можно поместить либы со старой сборки в отдельную папку и добавить
путь в QApplication::libraryPaths(), чтобы работала со своей версией Qt. или вообще сделать отдельный virtualenv со старой версией

Офлайн

#4 Сен. 4, 2017 01:44:55

Vady
Зарегистрирован: 2015-05-30
Сообщения: 70
Репутация: +  0  -
Профиль   Отправить e-mail  

Python 2.7.13 + QtGUI из комплекта Qt 4.8.6/4.8.7 в любых ОС = Segmentation Fault

Нашел вторую закономерную причину сегфолта.
Открываю форму одного человека, ничего не меняя данные, закрываю.
То же самое повторяю несколько раз до сегфолта.
Анализ показал, что сегфолт произошел после полного выполнения сигнала (даже принт, который самый последний из строк в функции, отобразился):

 def on_tabWidget_currentChanged(self, index):
Но! При предыдущих открываниях форм этот сигнал ни разу не срабатывал и не должен сработать (не трогал вкладки в форме, ибо закрывал через Alt+F4, то же самое повторил и через нажатие на крестик в правом верхнем углу окна)…
Как выяснить, откуда произошло срабатывание сигнала?


Прошу прощения за то, что ввел в заблуждение, не в том направлении копаю - консоль дебаггера выдал не полный вывод. На деле срабатывал всегда при каждом открывании.

Отредактировано Vady (Сен. 4, 2017 18:13:59)

Офлайн

#5 Сен. 4, 2017 01:51:51

Rodegast
От: Пятигорск
Зарегистрирован: 2007-12-28
Сообщения: 2683
Репутация: +  182  -
Профиль   Отправить e-mail  

Python 2.7.13 + QtGUI из комплекта Qt 4.8.6/4.8.7 в любых ОС = Segmentation Fault

Сигнал случайно не "destroyed()" называется?



С дураками и сектантами не спорю, истину не ищу.
Ели кому-то правда не нравится, то заранее извиняюсь.

Офлайн

#6 Сен. 4, 2017 11:46:36

Vady
Зарегистрирован: 2015-05-30
Сообщения: 70
Репутация: +  0  -
Профиль   Отправить e-mail  

Python 2.7.13 + QtGUI из комплекта Qt 4.8.6/4.8.7 в любых ОС = Segmentation Fault

Rodegast
Сигнал случайно не “destroyed()” называется?
Нет, tabWidget_currentChanged().
А по идее вызываться не должен никак!

Отредактировано Vady (Сен. 4, 2017 18:14:12)

Офлайн

#7 Сен. 4, 2017 22:39:07

Vady
Зарегистрирован: 2015-05-30
Сообщения: 70
Репутация: +  0  -
Профиль   Отправить e-mail  

Python 2.7.13 + QtGUI из комплекта Qt 4.8.6/4.8.7 в любых ОС = Segmentation Fault

Нашел вторую функцию, в которой произошел сегфолт.
И причем именно на obj.objectName()
Из принтов я вижу только:
'VisibleControlMixin.py 1-7_8'
Вот код функции:

     @classmethod
    def updateVisibleState(cls, children, invisibleObjectsNameList):
        """
        Обновляет состояние видимости всех объектов из списка children и их дочерних подобъектов.
        :param children: список объектов, для которых необходимо обновить состояние видимости
        :type children: list (of QObject)
        :param invisibleObjectsNameList: список имен объектов, которые необходимо скрыть
        :type invisibleObjectsNameList: list (of string)
        """
        needProcessingList = [children]
        processedNameList = []
        while needProcessingList:
            objList = needProcessingList.pop(0)
            for obj in objList:
                if isinstance(obj, QtGui.QTabWidget):
                    processedNameList.extend(cls.hideTabWidgets(obj, invisibleObjectsNameList))
                if isinstance(obj, QtGui.QWidget):
                    print 'VisibleControlMixin.py 1-7_8'
                    print obj.objectName()
                    print 'VisibleControlMixin.py 1-7_8-1'
                    objectName = forceString(obj.objectName())
                    if objectName in processedNameList:
                        continue
                    if objectName in invisibleObjectsNameList:
                        obj.setVisible(False)
                        if isinstance(obj, QtGui.QLabel):
                            buddy = obj.buddy()
                            if isinstance(buddy, QtGui.QWidget):
                                buddy.setVisible(False)
                        continue
                objChildren = obj.children()
                if objChildren: # добавить в стек просмотра дочерние элементы текущего виджета с обновлением частей имени
                    needProcessingList.append(objChildren)
Пока что встречаю сегфолты только в двух местах, а именно: obj.children() (не из этой функции, а в предыдущих постах!) и obj.objectName().
Всё никак не пойму где искать решение проблемы - или в коде, или в либах…
Кстати, перед сегфолтом obj имеет разные значения. Приведу те, которые попадались:
<PyQt4.QtGui.QScrollBar object at 0xad385adc>
<PyQt4.QtGui.QWidget object at 0xac9cc4f4>
<PyQt4.QtGui.QPushButton object at 0xaa1f4fa4>

Отредактировано Vady (Сен. 4, 2017 23:33:59)

Офлайн

#8 Сен. 6, 2017 00:36:25

Vady
Зарегистрирован: 2015-05-30
Сообщения: 70
Репутация: +  0  -
Профиль   Отправить e-mail  

Python 2.7.13 + QtGUI из комплекта Qt 4.8.6/4.8.7 в любых ОС = Segmentation Fault

Есть позитивный сдвиг! В функцию def setupDirtyCatherForObject(self, obj, exclude) добавил следующие строчки:

             elif isinstance(child, QtGui.QScrollBar):
                pass
            elif isinstance(child, QtGui.QPushButton):
                pass
То есть, чтобы не проверяли на наличие “детей” у этих объектов (у скроллбара и кнопки “детей” вроде нет и не будет).
В итоге функция приобрела следующий вид:
      def setupDirtyCatherForObject(self, obj, exclude):
        print obj
        if obj in exclude:
            return
        for child in obj.children():
            if isinstance(child, QtGui.QLabel) or child in exclude:
                pass
            elif isinstance(child, CDateEdit):
                self.connect(child, SIGNAL('dateChanged(QDate)'), self.on_dateEditChanged)
            elif isinstance(child, QtGui.QLineEdit):
                self.connect(child, SIGNAL('textChanged(QString)'), self.on_lineEditChanged)
            elif isinstance(child, QtGui.QTextEdit):
                self.connect(child, SIGNAL('textChanged()'), self.on_textEditChanged)
            elif isinstance(child, QtGui.QDateEdit):
                self.connect(child, SIGNAL('dateChanged(QDate)'), self.on_dateEditChanged)
            elif isinstance(child, QtGui.QComboBox):
                self.connect(child, SIGNAL('currentIndexChanged(int)'), self.on_comboBoxChanged)
            elif isinstance(child, QtGui.QCheckBox):
                self.connect(child, SIGNAL('stateChanged(int)'), self.on_checkBoxChanged)
            elif isinstance(child, QtGui.QSpinBox):
                self.connect(child, SIGNAL('valueChanged(int)'), self.on_spinBoxChanged)
            elif isinstance(child, QAbstractItemModel):
                self.connect(child, SIGNAL('dataChanged(QModelIndex, QModelIndex)'), self.on_abstractdataModelDataChanged)
                self.connect(child, SIGNAL('rowsInserted(QModelIndex, int, int)'), self.on_abstractdataModelDataChanged)
                self.connect(child, SIGNAL('rowsMoved(QModelIndex, int, int, QModelIndex, int)'), self.on_abstractdataModelDataChanged)
                self.connect(child, SIGNAL('rowsRemoved(QModelIndex, int, int)'), self.on_abstractdataModelDataChanged)
            elif isinstance(child, QtGui.QScrollBar):
                pass
            elif isinstance(child, QtGui.QPushButton):
                pass
            else:
                self.setupDirtyCatherForObject(child, exclude)
Как показало тестирование, работать с программой стал намного дольше, сегфолт произошел в другой функции: updateVisibleState. Позже исследую ее.
Только вот в данной функции не обрабатывал QWidget, о котором упоминал ранее в списке сегфолтов. Если попадется такой сегфолт, буду разбираться…

Updated:
Внес изменения в код функции updateVisibleState, добавив строчки:
                 if isinstance(obj, QtGui.QScrollBar):
                    continue
                if isinstance(obj, QtGui.QTPushButton):
                    continue
Теперь сама функция выглядит так:
      @classmethod
    def updateVisibleState(cls, children, invisibleObjectsNameList):
        """
        Обновляет состояние видимости всех объектов из списка children и их дочерних подобъектов.
        :param children: список объектов, для которых необходимо обновить состояние видимости
        :type children: list (of QObject)
        :param invisibleObjectsNameList: список имен объектов, которые необходимо скрыть
        :type invisibleObjectsNameList: list (of string)
        """
        needProcessingList = [children]
        processedNameList = []
        while needProcessingList:
            objList = needProcessingList.pop(0)
            for obj in objList:
                if isinstance(obj, QtGui.QScrollBar):
                    continue
                if isinstance(obj, QtGui.QTPushButton):
                    continue
                if isinstance(obj, QtGui.QTabWidget):
                    processedNameList.extend(cls.hideTabWidgets(obj, invisibleObjectsNameList))
                if isinstance(obj, QtGui.QWidget):
                    print 'VisibleControlMixin.py 1-7_8'
                    print obj.objectName()
                    print 'VisibleControlMixin.py 1-7_8-1'
                    objectName = forceString(obj.objectName())
                    if objectName in processedNameList:
                        continue
                    if objectName in invisibleObjectsNameList:
                        obj.setVisible(False)
                        if isinstance(obj, QtGui.QLabel):
                            buddy = obj.buddy()
                            if isinstance(buddy, QtGui.QWidget):
                                buddy.setVisible(False)
                        continue
                objChildren = obj.children()
                if objChildren: # добавить в стек просмотра дочерние элементы текущего виджета с обновлением частей имени
                    needProcessingList.append(objChildren)

Отредактировано Vady (Сен. 6, 2017 23:11:51)

Офлайн

#9 Сен. 28, 2017 23:47:07

Vady
Зарегистрирован: 2015-05-30
Сообщения: 70
Репутация: +  0  -
Профиль   Отправить e-mail  

Python 2.7.13 + QtGUI из комплекта Qt 4.8.6/4.8.7 в любых ОС = Segmentation Fault

Кое-что нашел по этой проблеме.
Чтобы смоделировать проблему, открываем форму, в которой происходит такая проблема, и закрываем. И повторяем несколько раз - происходит Segmentation Fault.
Опытным путем установил: если в методе, который вызывается в момент закрытия формы, удалить строчку sip.delete(dialog), то сегфолт не происходит. Но от этого после 30 минут работы объем занимаемой программой памяти вырос до 2Гб! Вернул строчку. Далее в файле, где происходит создание окна формы, закомментировал в классе диалогового окна всё содержимое методов _init_() и destroy(). По результатам теста сегфолтов нет. Последовательно раскомментировал строчки. После того как раскомментировал self.addModels('Visits', CF02512VisitsModel(self)), произошел сегфолт. Далее раскомментировал строчку del self.modelVisits внутри метода destroy() - сегфолт прекратился. Из этого сделал вывод: неудаленные старые модели и впоследствии созданные заново - одна из возможных причин сегфолта.
Далее раскомментировал self.addModels('ActionsSummary', CFxxxActionsSummaryModel(self, True)), предусмотрительно раскомментировав и в destroy() строчку del self.modelActionsSummary - произошел сегфолт. В ходе изучения принципа работы данного класса выяснил, что одна подмодель этой модели нигде по завершении работы не удаляется:

 class CActionsSummaryModel(CInDocTableModel):
    class CUetCol(CFloatInDocTableCol):
        def __init__(self, model):
            CFloatInDocTableCol.__init__(self, u'УЕТ',  'amount', 6, precision=2)
            self.model = model
Для решения проблемы прописал в destroy() формы:
 if hasattr(self.modelActionsSummary, 'colUET'):
    del self.modelActionsSummary.colUet.model
И после сегфолт прекратился. Сейчас раскомментирую оставшиеся строчки и ищу забытые к удалению модели.
А дальше… как говорится, чем дальше, тем темнее лес…

Использую команду sys.getrefcount(), чтобы узнать количество ссылок у объекта.
По результатам теста без команды del self.modelActionsSummary.colUet.model
sys.getrefcount(self.modelActionsSummary.colUet.model) выдает 4
sys.getrefcount(self.modelActionsSummary) выдает 4
Причем, эта проверка произошла До вызова команды del…
А после выполнения команды del self.modelActionsSummary.colUet.model
sys.getrefcount(self.modelActionsSummary) выдает 3.
У меня вопрос: как узнать, какие оставшиеся ссылки имеет объект self.modelActionsSummary?

Офлайн

  • Начало
  • » GUI
  • » Python 2.7.13 + QtGUI из комплекта Qt 4.8.6/4.8.7 в любых ОС = Segmentation Fault[RSS Feed]

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version