【Qt】为程序增加闪退crash报告日志

背景

随着软件代码量的增加,软件崩溃闪退的肯能行越来越大,其中一些是难以复现的,比如访问了访问了非法地址、被操作系统杀死等。

为此,在软件出现闪退情况时,尽可能多的记录闪退发生时信息,对排查闪退原因是非常有帮助的。

实现

因为闪退发生时软件已经不在运行了,因此需要在闪退前就告诉操作系统闪退后需要执行的操作,在Qt中就是在QApplicationexec()前调用操作系统提供的接口,注册闪退后的处理函数。

我们以Windows平台为例,在Windows平台,时利用SetUnhandledExceptionFilter函数实现异常(闪退)处理函数的注册的。

简单代码如下:

#include <QApplication>

#ifdef Q_OS_WIN
#include <windows.h>
#include <psapi.h>
#include <DbgHelp.h>
#include <fstream>
#include <sstream>

#pragma comment(lib, "DbgHelp.lib")
LONG WINAPI windowsCrashHandler(EXCEPTION_POINTERS* ex) {
    SYSTEMTIME time;
    GetLocalTime(&time);
    char logName[256];
    // 文件名格式crash_yyyymmdd_hhmmss.log
    sprintf(logName, "crash_%04d%02d%02d_%02d%02d%02d.log",
            time.wYear, time.wMonth, time.wDay,
            time.wHour, time.wMinute, time.wSecond);

    // 打开日志文件
    std::ofstream logFile(logName);
    if (!logFile.is_open()) return EXCEPTION_EXECUTE_HANDLER;

    // 记录异常信息
    logFile << "=== Exception: "
            << ex->ExceptionRecord->ExceptionCode
            <<" ==="
            << std::endl;

    // 记录内存占用(Windows)
    MEMORYSTATUSEX statex;
    statex.dwLength = sizeof(statex);
    if (GlobalMemoryStatusEx(&statex)) {
        logFile << "总内存:" << statex.ullTotalPhys / (1024 * 1024) << " MB" << std::endl;
    }

    PROCESS_MEMORY_COUNTERS pmc;
    GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc));
    logFile << "内存占用: "
            << pmc.WorkingSetSize / (1024 * 1024)
            << " MB" << std::endl;

    logFile << "Error Code: 0x" << std::hex << ex->ExceptionRecord->ExceptionCode << std::endl;

    // 获取调用堆栈
    HANDLE process = GetCurrentProcess();
    HANDLE thread = GetCurrentThread();
    SymInitialize(process, NULL, TRUE);  // 初始化符号表

    // 遍历堆栈帧
    STACKFRAME64 stackFrame = {{0}};
    stackFrame.AddrPC.Offset = ex->ContextRecord->Rip;  // x86 用 Eip, x64 用 Rip
    stackFrame.AddrPC.Mode = AddrModeFlat;
    stackFrame.AddrStack.Offset = ex->ContextRecord->Rsp;  // x86 用 Esp, x64 用 Rsp
    stackFrame.AddrStack.Mode = AddrModeFlat;
    stackFrame.AddrFrame.Offset = ex->ContextRecord->Rbp;  // x86 用 Ebp, x64 用 Rbp
    stackFrame.AddrFrame.Mode = AddrModeFlat;
    DWORD imageType;
#ifdef _M_IX86
    imageType = IMAGE_FILE_MACHINE_I386;
#elif _M_X64
    imageType = IMAGE_FILE_MACHINE_AMD64;
#endif

    logFile << "调用堆栈:" << std::endl;
    int frameNum = 0;
    while (StackWalk64(imageType, process, thread, &stackFrame, ex->ContextRecord,
                       NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) {
        // 获取符号信息
        BYTE symbolBuffer[sizeof(SYMBOL_INFO) + 256] = {0};
        SYMBOL_INFO* symbol = (SYMBOL_INFO*)symbolBuffer;
        symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
        symbol->MaxNameLen = 255;

        DWORD64 displacement = 0;
        if (SymFromAddr(process, stackFrame.AddrPC.Offset, &displacement, symbol)) {
            logFile << "[" << frameNum << "] " << symbol->Name << std::endl;
        } else {
            logFile << "[" << frameNum << "] Unknown Address" << std::endl;
        }
        frameNum++;
    }

    // 清理符号表
    SymCleanup(process);

    logFile.close();
    // 退出程序
    return EXCEPTION_EXECUTE_HANDLER;
}
#endif

int main(int argc, char *argv[])
{

#ifdef Q_OS_WIN
    // Windows 注册异常(闪退)处理函数
    SetUnhandledExceptionFilter(windowsCrashHandler);
#endif
    QApplication a(argc, argv);
    return a.exec();
}

这样在程序出现闪退后,就可以看到闪退时计算机内存的占用情况以及引起闪退的调用堆栈。

### Ubuntu 下应用程序安装后闪退的原因及解决方案 在 Ubuntu 系统下,某些应用程序可能在安装完成后运行时发生闪退现象。这种问题通常由多种因素引起,以下是常见的原因及其对应的解决方法: #### 1. **依赖库缺失** 许多应用程序需要特定版本的动态链接库才能正常工作。如果这些库未正确安装或版本不符合要求,则可能导致程序启动失败。 - 使用 `ldd` 工具检查目标可执行文件所需的共享库是否存在并加载成功: ```bash ldd /path/to/your/application | grep "not found" ``` 如果存在“not found”的条目,则说明缺少相应的库文件[^1]。 - 安装缺失的依赖项可以通过以下命令实现: ```bash sudo apt-get update && sudo apt-get install libmissing-dependency-name ``` #### 2. **权限不足** 有时,即使所有必要的依赖已满足,但如果程序试图访问受限资源(如设备节点或其他受保护路径),也可能引发异常终止。 - 验证是否有足够的权限来读取配置文件或者写入临时数据目录: ```bash strace -f -o trace.log your_application_name cat trace.log | grep denied ``` 这里会记录尝试操作被拒绝的日志信息[^2]。 #### 3. **环境变量设置不当** 部分图形化界面的应用特别敏感于 DISPLAY 变量以及其他 X Window System 或 Wayland 的相关参数定义情况;另外还有 LANG 和 LC_ALL 影响本地化的处理方式等。 - 设置合适的环境变量再试一次: ```bash export DISPLAY=:0;export LANG=en_US.UTF-8;./application_binary_file ``` #### 4. **硬件加速兼容性问题** 对于涉及 GPU 渲染的任务来说,驱动支持程度至关重要。旧版显卡驱动或许无法很好地适配现代框架需求从而造成崩溃。 - 关闭 OpenGL 加速功能测试稳定性差异: ```ini QT_XCB_FORCE_SOFTWARE_OPENGL=1 ./app_executable ``` 此外还可以考虑升级 NVIDIA/AMD Radeon/Mesa Drivers 至最新稳定发行版[^3]。 #### 5. **调试工具辅助分析** 为了更深入地了解具体的错误位置以及上下文条件,可以借助 gdb (GNU Debugger) 来捕获核心转储(Core Dump),进而定位根本诱因所在之处。 - 启用 core dump 功能以便收集更多诊断资料: ```bash ulimit -c unlimited echo "/tmp/core.%e.%p" | sudo tee /proc/sys/kernel/core_pattern ``` - 接着利用 GDB 对进程进行跟踪直至其意外结束为止: ```bash gdb --args application_path arguments... run bt full when crashed. ``` #### 6. **其他潜在触发点** 除了上述提到的技术层面之外,还可能存在诸如插件冲突、主题样式破坏用户体验一致性等问题影响正常使用体验。针对这种情况可以从简化初始状态做起逐步排除干扰源直到恢复正常运作行为模式为止[^4]^. --- ### 示例代码片段展示如何启用 Core Dumps 并通过 GDB 获取 Backtrace: ```bash # Step A: Enable core dumps and set pattern location ulimit -c unlimited echo "/tmp/core.%e.%p" | sudo tee /proc/sys/kernel/core_pattern # Step B: Launch the problematic app under GDB supervision gdb --args /usr/bin/my_problematic_app arg1 arg2 ... run # After crash occurs inside GDB session, generate backtrace report: bt full ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值