qt界面崩溃与假死问题

来源:互联网 发布:清除文件 linux 编辑:程序博客网 时间:2024/05/16 11:22

在开发图表项目时,项目要求如下:

同时打开100多个图表,单个图表的数据5W左右,结果图表出现了崩溃与假死的现象,每天好几次,不是必定出现现象,有的电脑未出现,有的电脑出现频繁

尝试了以下方式去解决问题:

首先出现了崩溃的现象

1.认为是历史修改代码导致,则通过svn查看历史版本的log,注释掉关键的代码继续测试

仍然崩溃

2.猜测是指针或者内存使用问题,则利用dbughelp配置在项目中,在用户环境测试,果然生成了dump文件,根据dump文件,修改了多线程使用内存的问题

仍然崩溃

3.但是此时不再生成dump文件,此时引入了压力测试,socket每秒发送1W~10W的数据,只有检查代码信号量的地方,发现list的append 和takefirst并不是线程安全的,果断加上锁

仍然崩溃

4.认为写文件线程可能存在问题,果断将写文件的线程从while循环改成moveToThread线程的方式,这样线程不需要使用锁了,通过信号槽实现传递数据


此时,界面不再崩溃,却出现了假死,即界面的图表不再更新,鼠标点击无响应,关闭发送数据,等待多久仍然假死,只能通过任务管理器结束程序

5.此时开始进行大量的压力测试,发现只开一个图表时,图表仍然会因为每秒10W的数据假死,图表描画一次的世界大约18ms,这个时候我们认识到GUI线程的描画能力有限,不可能同时或者连续的更新100多个图表,于是我们将图表对象存储管理起来,一个个描画,每描画一个,则用qApp->processEvent()让主线程去处理post事件或者系统事件而不是一直忙着描画事件,这里qApp->processEvent()有个潜在的风险需要注意:如果qApp->processEvent()所处的循环在读写内存,而在主线程处理其它事件时也访问了该内存,可能造成读写异常,所以qApp->processEvent()的范围和对内存的操作需要特别注意,并且限定每一个图表的最大数据量为10W

6:利用qdebug打印log记录到文件,图表却卡的更频繁,发现高频使用qdebug非常消耗性能,则去掉该方法

仍然假死,并且发现程序的内存会在某一时刻突然增加,增加到1.8G左右,然后界面假死

7.认为可能是写文件线程仍然可能存在问题,优化,从程序要写400左右个数的文件减少到300个左右,并且每个线程各写150个左右,减少文件的IO操作,文件不再不停打开关闭,把文件的指针存储管理起来,一开始打开,程序结束时关闭,并且调查了windows同时可以打开509个( 512-3)

8.开始使用内存泄露检测工具检查程序,后来发现作用甚微

仍然假死

9.这个时候只能换个角度思考了问题,采用了两个工具开始监控程序的cpu和内存使用记录,其中一个为windows性能监视器,发现程序在某一时刻内存会飙升

10.为了提高程序性能,尝试了批量发送数据和批量接收数据,批量发送数据和单个发送数据相比,内存差异不大,cpu降低5%

11.认为自己写的程序不再有内存泄露,那是不是QT的问题呢?或者没有用好QT呢? 答案是肯定的,我们开始猜测是信号量的问题,因为信号量跨线程在不断的拷贝,这个时候进行了demo程序测试,所谓demo程序就是一个线程负责发送数据,一个线程接收数据,尽量简单,发现当两个线程的处理为空时,一秒放松百万信号,程序运行正常,因为QT的每秒信号量处理数约为600W左右,但是只要接收线程对收到的数据进行一点数据处理,如QString::number,实际测试大约每接收一次数据,有50次左右的QString::number,发现界面果断卡死,这个时候真相快要大白了,界面假死原因可以理解成信号量阻塞了,利用windows api 打印cpu轮转,计算前面50次左右的处理时间,约为0.15ms,显然,生产者速度过快,消费者处理较慢就会阻塞


真相大白:生产者和消费者的速度不匹配导致了图表假死,解决办法:将消费者的部分数据处理移到生产者中,相当于间接的适当的阻塞一下生产者,并且提高消费者的速度,这样,生产者和消费者速度匹配。就解决了界面假死的问题


赠送名言:你在乎的人越多,你就越脆弱

1 0
原创粉丝点击