Qt环境生成dump文件解决程序异常崩溃以及生成日志文件

news2025/2/21 19:47:31

一、背景

1、在测试自己的项目代码过程

① 程序的编译的时候没有报错,程序在Qt release模式下运行程序,程序运行五个小时后异常退出,The process was ended forcefully;② 以及在项目程序通过windeployqt 工具打包发布的程序(排出网上所说缺乏动态依赖库)仍然运行五个小时后异常退出The process was ended forcefully,没有提示的问题。
在这里插入图片描述

2、调试项目代码排出bug过程

由于项目主要是具有4个功能,测试第1个功能,将剩下的3个功能注释完进行测试,发现长时间运行没有出现程序异常退出的情况;接着对第1个和第2个功能进行测试,剩下2个功能注释,就发现 ① Qt 对sqlite数据库操作存在内存泄漏问题,以及对同一份数据库进行同时读写的时候没有加锁造成的问题,② 如果是多个子线程操控数据库的时候,记得加锁,防止造成资源争夺

(1)解决对sqlite数据库操作内存泄漏问题

Qt 对sqlite数据每一次对增删改查操作是不是会占用内存资源,然后这种情况下没有释放数据库资源,解决办法如下。
参考:Qt sqlite 查询内存泄漏

query.clear();

(2)同一份数据库进行同时读写时加互斥锁

参考:QT-多线程与MySQL数据库

线程互斥(Mutex):是指对于共享的进程系统资源,在各单个线程访问时的排它性。当有很多个线程都要使用某一共享资源时,任何时刻最多只允许一个线程去使用,其它要使用该资源的线程必须等待,直到占用资源者释放该资源才能被其他线程使用。也是代码中的上锁(mutex.lock)和解锁(mutex.unlock)。

互斥对象:互斥对象和临界区很像,采用互斥对象机制,只有拥有互斥对象的线程才有访问公共资源的权限。因为互斥对象只有一个,所以能保证公共资源不会同时被多个线程同时访问。当前拥有互斥对象的线程处理完任务后必须将线程交出,以便其他线程访问该资源。

方法:由于项目还没有完成,所以后期对同一份数据库文件进行操作的时候加上互斥锁,后续补充相关代码。

二、具体操作

1、生成dump文件

参考1:Qt环境生成dump解决异常崩溃
参考2:Qt-生成dump文件

2、.pro文件配置

QMAKE_CXXFLAGS_RELEASE = $$QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO
QMAKE_LFLAGS_RELEASE = $$QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO,
QMAKE_LFLAGS_RELEASE = /INCREMENTAL:NO /DEBUG

# test crash
QMAKE_CFLAGS_RELEASE += -g
QMAKE_CXXFLAGS_RELEASE += -g
QMAKE_CFLAGS_RELEASE -= -O2
QMAKE_CXXFLAGS_RELEASE -= -O2
QMAKE_LFLAGS_RELEASE = -mthreads -W

# 方便生成DUMP调试
LIBS += -lDbgHelp
QMAKE_LFLAGS_RELEASE = /INCREMENTAL:NO /DEBUG

QMAKE_CXXFLAGS += -g
QMAKE_CFLAGS += -g

# 调试信息以及pdb文件
QMAKE_CXXFLAGS_RELEASE = $$QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO
QMAKE_CFLAGS_RELEASE = $$QMAKE_CLAGS_RELEASE_WITH_DEBUGINFO
QMAKE_LFLAGS_RELEASE = $$QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO

3、工程文件中添加ccrashstack类

资源

4、封装生成.dmp和日志文件代码

outputDump.h文件
参考:Qt环境生成dump解决异常崩溃

#ifndef OUTPUTDUMP_H   //避免同一个文件只会被包含一次
#define OUTPUTDUMP_H

//#pragma once         //避免同一个文件只会被包含一次
#include"ccrashstack.h"
#include <shlobj.h>
#include <QDebug>
#include <DbgHelp.h>
#include <QDateTime>
#pragma comment(lib, "dbghelp.lib")  //使用注释方式引入库dbghelp.lib或编译目录。

/*------------------生成dump文件------------------------*/
LONG crashHandler(EXCEPTION_POINTERS *pException)
{
    QString curDataTime = QDateTime::currentDateTime().toString("yyyyMMddhhmmss");
    QString dumpName = curDataTime + ".dmp";

    HANDLE dumpFile = CreateFile((LPCWSTR)QString("./" + dumpName).utf16(),GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if(dumpFile != INVALID_HANDLE_VALUE)
    {
        MINIDUMP_EXCEPTION_INFORMATION dumpInfo;
        dumpInfo.ExceptionPointers = pException;
        dumpInfo.ThreadId = GetCurrentThreadId();
        dumpInfo.ClientPointers = TRUE;

        MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),dumpFile, MiniDumpNormal, &dumpInfo, NULL, NULL);
        CloseHandle(dumpFile);
    }
    else
    {
        qDebug() << "dumpFile not vaild";
    }

    return EXCEPTION_EXECUTE_HANDLER;
}

//防止CRT(C runtime)函数报错可能捕捉不到
void DisableSetUnhandledExceptionFilter()
{
    void* addr = (void*)GetProcAddress(LoadLibrary(L"kernel32.dll"), "SetUnhandledExceptionFilter");
    if(addr)
    {
        unsigned char code[16];
        int size = 0;

        code[size++] = 0x33;
        code[size++] = 0xC0;
        code[size++] = 0xC2;
        code[size++] = 0x04;
        code[size++] = 0x00;

        DWORD dwOldFlag, dwTempFlag;
        VirtualProtect(addr, size, PAGE_READWRITE, &dwOldFlag);
        WriteProcessMemory(GetCurrentProcess(), addr, code, size, NULL);
        VirtualProtect(addr, size, dwOldFlag, &dwTempFlag);
    }
}

#endif // OUTPUTDUMP_H

outputLog.h

#ifndef OUTPUTLOG_H
#define OUTPUTLOG_H  //避免同一个文件不会被包含多次 条件编译 满足一定条件下才会被编译

//#pragma once       //避免同一个文件不会被包含多次
#include <QDir>
#include <QFile>
#include <QMutex>
#include <QTextStream>
#include <QTime>

#include"ccrashstack.h"

/*---------------打日志文件----------------------*/
void outputMessage(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    static QMutex mutex;
    mutex.lock();
    QString text;
    switch(type)
    {
    case QtDebugMsg:
        text = QString("Debug:");
        break;
    case QtWarningMsg:
        text = QString("Warning:");
        break;
    case QtCriticalMsg:
        text = QString("Critical:");
        break;
    case QtFatalMsg:
        text = QString("Fatal:");
    }
    QString context_info = QString("File:(%1) Line:(%2)").arg(QString(context.file)).arg(context.line);
    QString current_date_time = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss ddd");
    QString current_date = QString("(%1)").arg(current_date_time);
    QString message = QString("%1 \r\n%2 %3 \r\n%4").arg(current_date).arg(text).arg(context_info).arg(msg);

    //判断文件夹是否存在,不存在新建
    QString aFile = QDir::currentPath() + "/LogFile";
    QDir dir(aFile);
    if(!dir.exists())
    {
        dir.mkdir(aFile);//只创建一级子目录,即必须保证上级目录存在
    }

    QString current_time = QDateTime::currentDateTime().toString("yyyyMMdd");
    QFile file(aFile+"/log"+current_time+".txt");
    file.open(QIODevice::WriteOnly | QIODevice::Append);
    QTextStream text_stream(&file);
    text_stream << message << "\r\n \r\n";

    file.flush();
    file.close();
    mutex.unlock();
}
#endif // OUTPUTLOG_H

main.c 中添加完#include"outputDump.h"和#include"outputLog.h" 头文件,直接调用以下函数,注意放置的位置。如下所示:
1、注冊异常捕获函数,生成.dmp文件。

SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)crashHandler);
DisableSetUnhandledExceptionFilter();

2、注册MessageHandler,生成日志文件。

 qInstallMessageHandler(outputMessage);
#include "mainwindow.h"
#include <QApplication>
#include"outputDump.h" //生成dump头文件
#include"outputLog.h"  //生成日志头文件

int main(int argc, char *argv[])
{
    /*-------1、注冊异常捕获函数 生成.dmp文件--------*/
    SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)crashHandler);
    DisableSetUnhandledExceptionFilter();

    QApplication a(argc, argv);

    /*-------2、注册MessageHandler 生成日志文件--------*/
    qInstallMessageHandler(outputMessage);

    MainWindow w;
    w.show();
    return a.exec();
}

三、测试效果

1、程序异常退出测试代码

void MainWindow::on_crashBtn_clicked()
{
    QString *p = NULL;
    p->clear();
}

2、Qt-release编译生成.dmp文件和日志文件

在这里插入图片描述
在这里插入图片描述

3、使用VS2017定位代码出错位置

直接把.dmp文件拖入VS2017软件下。
在这里插入图片描述

在这里插入图片描述

四、小结

1、感谢技术交流群的大佬、师兄、代工在调试和测试代码过程中对我的指导和帮助,帮助我顺利解决问题。
2、由于此次项目的出现的问题是sqlite内存泄漏以及数据库文件操作没有加锁两个问题,生成.dmp文件在VS2017中调试不了,且所占字节为0Kb,目前自己也没有搞懂这个问题,所有的时候调试代码还得需要经验。如果哪位大佬知道这个问题麻烦指导一下,感谢。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/167583.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

用最简单的方式告诉你什么是集线器、交换机、路由器

欢迎来到东用知识小课堂&#xff01;某一天&#xff0c;你到你女友小芳(暂定这个名字吧)就读的学校去找她&#xff0c;那么你的做法是什么呢&#xff1a;一、集线器的工作方式&#xff1a;你站到学校中庭&#xff0c;大喊一声“小芳&#xff0c;我来你找你了!”(广播)如果这个时…

〖百宝书-思维锻炼①〗——思维进阶和升华

大家好&#xff0c;我是涵子&#xff0c;欢迎大家今天进入了新专题&#xff1a;百宝书-思维锻炼&#xff01; &#x1f4ac; 人生格言&#xff1a;Stay foolish, stay kind.&#x1f4ac; &#x1f4eb; 如果文章知识点有错误的地方&#xff0c;请指正&#xff01;和大家一起学…

SpringSecurity随笔(2)-OAuth2协议

短信登录 参考密码登录过程 1.编写短信登录过滤器&#xff0c;验证短信验证码 2.编写未认证得SmsAuthenticationToken 3.将未认证的SmsAuthenticationToken传递给AuthenticationManager 4.编写一个SmsAuthenticationProvider 5.调用UserDetialsService获取用户信息 OAuth协议…

【Linux杂篇】经常登录Linux,用户密码背后的知识了解一下

一&#xff0c;用户密码存放在哪里&#xff1f; 说到这个问题&#xff0c;绝大部分的同学肯定都知道/etc/passwd这个文件&#xff0c;不错&#xff0c;这个文件里存储的就是用户名&#xff0c;密码等信息。 每一行都是一个account&#xff0c;每一行有7个信息&#xff0c;分…

在农业银行做开发是什么样的体验?

本文已经收录到Github仓库&#xff0c;该仓库包含计算机基础、Java基础、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等核心知识点&#xff0c;欢迎star~ Github地址&#xff1a;https://github.com/…

MySQL环境搭建

文章目录1. MySQL的卸载步骤1&#xff1a;停止MySQL服务步骤2&#xff1a;软件卸载步骤3&#xff1a;残余文件的清理步骤4&#xff1a;清理注册表步骤5&#xff1a;删除环境变量配置2. MySQL的下载、安装、配置MySQL的4大版本软件的下载MySQL8.0 版本的安装配置MySQL8.0配置MyS…

超详解通讯录,保姆式教学 ,轻松学会实现通讯录的功能【c语言】

文章目录静态通讯录Contact.htest.c菜单的创建Contact.c初始化通讯录InitContact的实现增加联系人AddContact的实现查找指定联系人的信息SearchContact的实现删除指定联系人DelContact的实现修改指定联系人的信息ModifyContact的实现显示所有联系人的信息ShowContact的实现完整…

vite项目为什么可以直接使用NODE_ENV?

背景 我们知道&#xff0c;在process.env中并没有NODE_ENV这个变量&#xff0c;但是我们却可以在项目的代码中使用process.env.NODE_ENV这个值来判断当前是development环境还是production环境&#xff0c;然后进行后续的逻辑操作。 这说明&#xff0c;在vite内部&#xff0c;…

大数据面试题集锦-Hadoop面试题(二)-HDFS

你准备好面试了吗?这里有一些面试中可能会问到的问题以及相对应的答案。如果你需要更多的面试经验和面试题&#xff0c;关注一下"张飞的猪大数据分享"吧&#xff0c;公众号会不定时的分享相关的知识和资料。 1、 HDFS 中的 block 默认保存几份&#xff1f; 默认保存…

MacBook Pro外接显示器竖屏显示

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3;哈喽&#xff01;大家好&#xff0c;我是「奇点」&#xff0c;江湖人称 singularity。刚工作几年&#xff0c;想和大家一同进步&#x1f91d;&#x1f91d;一位上进心十足的【Java ToB端大厂领…

接口性能测试避坑 Django+Nginx+uwsgi接口性能调优postman Apifox ab

Django开发了个接口供外部调用&#xff0c;Django的并发性能弱早有所闻&#xff0c;所以采用DjangoNginxuwsgi架构来提高并发量。然后使用测试工具测试并发量。服务器配置&#xff1a;CPU 2&#xff0c;内存8G接口内容只有3句&#xff1a;request_data {"code":&quo…

MyBatis复习

本文章根据尚硅谷MyBatis教程整理而来 原视频地址&#xff1a;https://www.bilibili.com/video/BV1VP4y1c7j7 MyBatis简介 MyBatis历史 MyBatis最初是Apache的一个开源项目iBatis, 2010年6月这个项目由Apache Software Foundation迁 移到了Google Code。随着开发团队转投Goo…

力扣刷题记录——521. 最长特殊序列 Ⅰ、541. 反转字符串 II、557. 反转字符串中的单词 III

本专栏主要记录力扣的刷题记录&#xff0c;备战蓝桥杯&#xff0c;供复盘和优化算法使用&#xff0c;也希望给大家带来帮助&#xff0c;博主是算法小白&#xff0c;希望各位大佬不要见笑&#xff0c;今天要分享的是——《521. 最长特殊序列 Ⅰ、541. 反转字符串 II、557. 反转字…

PhotoZoom Pro8全新版本功能介绍及系统要求

PhotoZoom 2023&#xff08;PhotoZoom 8&#xff09;全新版本震撼来袭。 一款划时代的、技术上产生革命性影响的数码图片放大工具。 我们获取图片的方法&#xff0c;一般是从度娘图片和各个图库里找素材。但一般网上搜索到的很多图片像素都非常小&#xff0c;普通方法放大就像打…

修改配置文件的定时任务

1.问题背景 下发文件给下游系统设置的是定时任务&#xff0c;原本是每天的18&#xff1a;08定时发送&#xff0c;突然下游说要立马发送&#xff0c;于是只能去修改定时任务。 2.修改操作 查看权限—修改权限—备份–修改—重启 查看权限 进入配置文件目录&#xff1a;cd /…

分享77个HTMLCSS源码,总有一款适合您

HTML&CSS源码 分享77个HTML&CSS源码&#xff0c;总有一款适合您 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c;大家下载后可以看到。 源码下载链接&#xff1a;https://pan.baidu.com/s/1QRSokzVy2ZAaSD6VR…

DataGear 4.4.0 发布,数据可视化分析平台

DataGear 4.4.0 发布&#xff0c;带来看板新特性&#xff0c;具体更新内容如下&#xff1a; 新增&#xff1a;看板新增dg-chart-manual-render属性&#xff0c;用于控制是否手动渲染图表&#xff1b;新增&#xff1a;看板dg-dashboard-code属性新增"instance"值&…

Linux——线程概念及私有数据和优缺点

目录 一.什么是线程 二.线程私有的数据 三.线程的优点 四.线程的缺点 五.线程与进程对比 一.什么是线程 线程是在进程内部运行&#xff0c;一个进程可以有多个线程。 打个比方&#xff0c;假如人是一个进程&#xff0c;那么走路、思考、吃饭、说话作为不同的线程。一个进…

《Linux Shell脚本攻略》学习笔记-第十章

10.1 Linux的生态系统由网络、硬件、负责分配资源的操作系统内核、接口模块、系统实用工具以及用户程序所组成的。 10.2 运行在计算机中的多个进程都被分配了一个被称为进程ID的唯一标识数字。进程属性包括拥有该进程的用户、进程使用的内存数量、进程占用的CPU时间。 ps命令默…

拉伯证券|年内第二大解禁周来袭

Wind数据显现&#xff0c;除掉新上市公司&#xff0c;本周A股共有54家公司限售股解禁&#xff0c;解禁数量270.57亿股&#xff0c;以最新收盘价计算&#xff08;下同&#xff09;&#xff0c;解禁市值1752.90亿元&#xff0c;为年内第二大解禁周。 本周解禁市值超越10亿元的公司…