【问题标题】:Segmentation fault on exit in pyQt5 but not pyQt4在 pyQt5 但不是 pyQt4 退出时出现分段错误
【发布时间】:2016-08-23 17:56:56
【问题描述】:

this answer 中给出的退出时崩溃的解决方法适用于 pyqt4。

但不使用 pyqt5,它经常(超过一半的时间)出现分段错误。

只有导入行改变了

#!/usr/bin/python

import sys

#toolkit = "Qt4"
toolkit = "Qt5"
if toolkit == "Qt4":
  # Qt4 (no crash)
  from PyQt4.QtCore import *
  from PyQt4.QtGui import *
elif toolkit == "Qt5":
  # Qt5 (crash)
  from PyQt5.QtWidgets import (
    QApplication, QGraphicsScene, QGraphicsView
  )


app = QApplication(sys.argv)

grview = QGraphicsView()

# no crash
scene = QGraphicsScene(parent=grview)

grview.setScene(scene)

grview.show()

sys.exit(app.exec_())

这是回溯,from the core dump(作为旁注,在 gdb 内部,没有崩溃)

[New LWP 4684]
[New LWP 4683]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Core was generated by `python grview_qt5.py'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x00007f5233393e69 in ?? ()
(gdb) bt
#0  0x00007f5233393e69 in  ()
#1  0x00007f522fee6f20 in  ()
#2  0x0000000000e0d340 in  ()
#3  0x00007f522fee6f20 in  ()
#4  0x0000000000e0d5f0 in  ()
#5  0x00007f523e0bc000 in _rtld_local () at /lib64/ld-linux-x86-64.so.2
#6  0x00007f523ae7285f in QThreadPrivate::start(void*) (arg=0xe0d340) at thread/qthread_unix.cpp:337
#7  0x00007f523d8780a4 in start_thread (arg=0x7f522fee7700) at pthread_create.c:309
#8  0x00007f523d5adcbd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
(gdb) info threads
  Id   Target Id         Frame 
  2    Thread 0x7f523e06f700 (LWP 4683) 0x00007f523deb21c7 in munmap () at ../sysdeps/unix/syscall-template.S:81
* 1    Thread 0x7f522fee7700 (LWP 4684) 0x00007f5233393e69 in ?? ()

为什么pyqt4和pyqt5有区别?

肯定和Object Destruction on Exit有关系,但是怎么回事?

避免这种崩溃的正确方法是什么?

【问题讨论】:

  • python3 删除对象的时间与 python2 不同。尝试在 sys.exit 之前对对象使用显式 del:del grview;del scene;del app;.
  • QtCore.QTimer.singleShot(1000, app.quit) 替换所有图形内容,这样就只创建了一个QApplication。如果仍然崩溃,请尝试使用QCoreApplication。这可能有助于缩小问题的根源。
  • @ekhumoro 将所有图形内容替换为QTimer.singleShot(1000, app.quit),没有崩溃。

标签: crash segmentation-fault pyqt pyqt4 pyqt5


【解决方案1】:

我无法使用 Fedora 24 的 PyQt 使您的示例崩溃。

但是我也看到了这个问题,并且没有关于如何在 python 退出之前清理 Qt 对象的明确答案。我的应用程序有 1000 多个 Qt 对象,我完全不知道如何跟踪所有无法清理的对象。

我认为关键是你必须以相反的构造顺序删除你创建的所有对象。注意从任何引用了其他对象的 Qt 对象中删除对象。例如布局中的小部件。

正如我在评论中所说,差异来自从 python2 到 python3 的更改,与对象删除和垃圾收集有关。

使用 sys.exit() 来避免清理是不够的。

您需要使用 os._exit(code) 来阻止 python 运行 onExit 处理程序。这更有可能抑制 seg 故障。但是您需要确保运行任何重要的 onExit 处理程序。例如删除临时文件。

尝试像这样退出,看看问题是否会消失。

grview.show()
rc = app.exec_()

del grview
del scene
del app

sys.exit( rc )

【讨论】:

  • 在这两种情况下我都使用了相同的python版本(Python 2.7.12),那么“从python2到python3的变化”如何解释差异?
  • Qt 版本为 4.8.6 和 5.4.2
  • 有了您的建议,没有崩溃。交换 del 场景和 del grview 线也没有崩溃。按顺序删除应用程序、场景和grview,也没有崩溃。实际上del grviewdel scene 并不是防止崩溃所必需的。只有del app 很重要。为什么?
  • @ederag。这里唯一真正的问题是 pyqt/python 删除对象的顺序。使用del 可以改变顺序,甚至可以通过重命名变量来实现。本质上,pyqt/python 是在删除对象时迭代一个字典,字典条目的顺序是严格undefined。 pyqt4 和 pyqt5 之间的区别在于,默认情况下,前者在退出时会自动调用其拥有的任何对象的 C++ 析构函数,但后者不会。所以你也可以尝试为 pyqt5 添加import sip; sip.setdestroyonexit(True) 看看是否有任何不同。
  • @ekhumoro 感谢您的“dict”解释。但相反,删除的顺序似乎并不重要。见我之前的评论。使用sip.setdestroyonexit(True),它也经常崩溃。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-02-21
  • 1970-01-01
  • 1970-01-01
  • 2017-04-14
  • 1970-01-01
  • 2016-10-27
  • 1970-01-01
相关资源
最近更新 更多