C++(Qt)软件调试---内存分析工具Heob(26)

C++(Qt)软件调试—内存分析工具Heob(26)


文章目录

  • C++(Qt)软件调试---内存分析工具Heob(26)
    • @[toc]
    • 1、概述🐜
    • 2、环境配置🪲
    • 3、功能说明
    • 4、使用Heob分析qt 程序内存泄漏🦧
    • 5、使用Heob检测qt 程序野指针/内存越界👓
    • 6、使用Heob检测qt 程序空指针/throw抛出异常👕
    • 7、使用Heob检测qt 程序重复释放👗
    • 8、使用Heob检测qt 程序长生命周期式内存泄漏👙
    • 9、相关地址🐐

更多精彩内容
👉内容导航 👈
👉C++软件调试 👈

1、概述🐜

绝大部分的文章都说Heob是一个内存泄漏分析工具,其实Heob只是内存泄漏分析功能比较突出,实际上Heob可以分析很多内存问题。

Heob是一个Windows下检测缓冲区溢出(野指针、空指针、内存越界、重复释放、异常捕获等)和内存泄漏的工具,集成到Qt Creator中,功能强大,简单容易上手。

  • 支持MSVC和MinGW编译器编译的程序内存泄漏检测;

  • 支持32位和64位程序;

  • 不支持Linux;

  • 支持设置过滤内存泄漏字节大小;

  • 支持异常处理;

  • 支持与Qt调试器、事后调试器联动;

  • 支持将分析结果导出位xml文件,后续通过加载xml文件查看分析结果;

  • Qt Creator支持4.6以上版本,低版本没有这个功能,可以自行安装高版本的QtCreator(注意:不是Qt版本,是IDE版本)。

  • 处理速度块,占用资源少。

在Qt中使用Heob分析内存泄漏有4种用法:

  • 方法1: 使用Heob分析MSVC编译生成的程序,对于 PDB 调试信息,使用 dbghelp.dll,速度块;

  • 方法2: 使用Heob分析MinGW编译生成的程序, 对于DWARF 调试信息 (gcc) ,需要下载dwarfstack.dll库到Heob路径下才可以使用,性能会低很多;

在这里插入图片描述

  • 方法3: 使用Heob分析MinGW编译生成的程序,通过cv2pdb将DWARF 转成PDB进行分析,性能和分析MSVC编译的程序差不多。
  • 方法4: 命令行运行。

注意:

  • MSVC版本<=2017时,Heob检测会出现误报,将内存泄漏包位外部错误的内存泄漏,所以如果使用的编译器版本比较低,过滤设置时就需要勾选上外部错误 项;
  • 对MinGW和MSVC支持不同,有些情况使用MSVC编译器可以检测出来,使用MinGW检测不出来,有些情况相反。
  • 运行Heob前需要保证代码已经完成编译并生成了可执行程序。

演示环境:

环境版本
系统Windows11
开发环境Qt5.9、Qt5.12.12、Qt5.14.2、Qt6.8
IDEQt Creator 5、Qt Creator 10、Qt Creator 14、Qt Creator 15
编译器mingw730_64、mingw1310_64、MSVC2015-64、MSVC2017-64、MSVC2022-64
分析工具Heob 4.0
依赖库dwarfstack 2.2

2、环境配置🪲

  • 下载Heob 4.0和dwarfstack 2.2 解压到同一个文件夹中;

  • 打开Qt Creator,选中【分析】【Heob】;

在这里插入图片描述

  • 打开Heob窗口后点击【浏览】选择Heob路径,然后点击右下角图标保存配置。

    在这里插入图片描述

  • 创建一个Qt工程,测试代码如下所示

#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QMessageBox>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
}

Widget::~Widget()
{
    delete ui;
}

class Test
{
public:
    Test()
    {
        p = new int;
    }

private:
    int* p;
};

/**
 * @brief  内存泄漏1
 */
void Widget::on_pushButton_clicked()
{
    Test* test = new Test();
    free(test);
}


void fun()
{
    for(int i = 0; i < 1024; i++)
    {
        int*p = new int[1000];
        qDebug() << p[1];
    }
}
/**
 * @brief 内存泄漏2
 */
void Widget::on_pushButton_2_clicked()
{
    fun();
}

/**
 * @brief 野指针1
 */
void Widget::on_pushButton_3_clicked()
{
    int* p = new int;
    delete p;
    *p = 123;
}

/**
 * @brief 野指针2
 */
void Widget::on_pushButton_4_clicked()
{
    int* p;
    *p = 123;
}

/**
 * @brief 空指针
 */
void Widget::on_pushButton_5_clicked()
{
    int* p = nullptr;
    *p = 123;
}

/**
 * @brief 内存越界
 */
void Widget::on_pushButton_6_clicked()
{
    int*p = new int[12];
    p[123] = 123;
    p[12] = 1234;
    delete[] p;
}

/**
 * @brief 重复释放
 */
void Widget::on_pushButton_7_clicked()
{
    int*p = new int[12];
    p[1] = 123;
    delete[] p;
    delete[] p;
}

/**
 * @brief 抛出异常
 */
void Widget::on_pushButton_8_clicked()
{
    throw 123;
}

/**
 * @brief 成员数组添加数据
 */
void Widget::on_pushButton_9_clicked()
{
    for(int i = 0; i < 10000; i++)
    {
        m_list.append(new int);
        qDebug() << i;
    }
}


QList<int*> g_list;
/**
 * @brief 全局数组添加数据
 */
void Widget::on_pushButton_10_clicked()
{
    for(int i = 0; i < 10000; i++)
    {
        g_list.append(new int);
        qDebug() << i;
    }
}

/**
 * @brief 释放内存
 */
void Widget::on_pushButton_11_clicked()
{
    for(int i = 0; i < m_list.count(); i++)
    {
        delete m_list[i];
    }
    for(int i = 0; i < g_list.count(); i++)
    {
        delete g_list[i];
    }
    m_list.clear();
    g_list.clear();
    QMessageBox::about(this, "注意!", QString("已经释放内存:%1  %2").arg(m_list.count()).arg(g_list.count()));
}


在这里插入图片描述

3、功能说明

  • 详细功能说明可以打开命令行,使用heob.exe -H命令查看;

如图所示:

在这里插入图片描述

  • 点击【新建/删除】可以创建新的配置文件;

  • 点击右下角软盘图标可以保存配置,配置文件保存在C:\Users\MHF\AppData\Roaming\QtProject\QtCreator.ini文件中;

  • 点击【OK】开始进行分析。

  • Heob Path: 下载解压的Heob.exe文件路径;

  • XML output file: 生成的xml文件名称,使用的相对路径,在可执行程序路径下,后续可通过【调试】窗口中的文件夹图标加载生成的xml文件;

    在这里插入图片描述

  • Handle exceptions: 设置出现异常时的处理方式

    • 设置为On则使用Heob处理,出现异常时程序退出,在调试窗口显示出现异常的信息;
    • 设置为Off则在出现异常时,会使用事后调试器进行调试。
    • 设置为Only则禁用所有Heob功能,除了安装异常处理程序。如果应用程序崩溃,则只显示崩溃的堆栈跟踪,不检测内存泄漏。因此,当在控制台上使用Heob或为子进程运行Heob时,此选项非常有用。

    在这里插入图片描述

  • Run with debugger: 勾选上后会以Debug调试模式运行,当出现异常(例如空指针野指针)时会触发断点,定位到出现异常的位置;

在这里插入图片描述

  • Raise breakpoint exception on error: 表示出现异常时触发断点,(主要用于重复释放)
    • 如果没勾选,则出现重复释放内存越界等问题时,不会触发异常断点,会将检测结果写入文件;
    • 如果勾选上后,并且勾选了Run with debugger,则出现重复释放内存越界等问题时,将会触发异常断点;

在这里插入图片描述

  • Page protection: 这个功能更适合用于检测内存越界、野指针;
    • 选择OFF时更适合检测内存泄漏;
    • 选择After后会在分配的内存块末尾设置一个保护页,当访问到这个保护页时就会触发异常,从而识别出野指针、内存越界;
    • 选择Before则会再分配的内存块前设置一个保护页;
    • 这个功能会消耗内存、降低检查速度,建议仅用于64位或短时间运行的程序。

在这里插入图片描述

  • Freed memory protection: 这个功能会增加释放内存保护功能,已经释放的内存就不会再被使用,对于检测野指针、重复释放问题有用,但是会大量消耗内存。
  • Leak details: 这个选项用于设置程序退出时融合处理收集到的内存泄漏数据,不同的设置影响分析结果和处理速度;
    • None:表示不收集内存泄漏数据,所以退出时速度最快;
    • Simple:表示将所有未释放的内存写入结果文件,速度最慢,生成的xml文件也最大,所有内存泄漏分析结果都会被记录为16 bytes in 1 blocks are lost in loss record 196 of 209 (#2513),无法通过过滤器进行过滤;
    • Detect Leak Types:会记录所有确定的直接内存泄漏、间接内存泄漏到文件中,速度会快一些;
    • Detect Leak Types (Show Reachable):除了记录所有确定的直接内存泄漏、间接内存泄漏到文件中,还会将可能存在内存泄漏的结果记录到文件中,可以通过过滤器中【可能的内存泄漏】选项过滤;
    • Fuzzy Detect Leak Types:选择模糊检测泄漏类型来标记内存块,或者它们是否引用了任何地址。当使用一些自定义分配器(例如:ffmpeg的av_malloc())时,此选项很有用,检测结果最少,只保留最有可能内存泄漏的记录,速度快,生成的文件小;
    • Detect Leak Types (Show Reachable) :与Fuzzy Detect Leak Types类似,不过会将其它的记录认为是可能存在的内存泄漏,也会记录到文件中,可以通过过滤器中【可能的内存泄漏】选项过滤。

在这里插入图片描述

  • Minimum leak size: 设置记录内存泄漏的最小字节数,低于设置值的内存泄漏不会被记录;

在这里插入图片描述

  • Control leak recording: 控制记录内存泄漏的开关、记录时间段等,更加灵活的记录分析内存泄漏的功能(例如记一个数组不断添加堆内存数据,很长一段时间才会释放一次,这种就是特殊情况的内存泄漏,就可以通过n/f快捷键来控制检测);

    • OFF:关闭终端,始终开启内存泄漏记录;
    • On (Start Disabled):打开终端,Heob启动时不记录内存泄漏,可在终端中进行控制;
    • On (Start Enabled):打开终端,Heob启动时就开始记录内存泄漏,并且可在终端中进行控制。

    在这里插入图片描述

  • Extra arguments: 用于输入运行其它Heob参数,例如输入-vleaks.svg会将检测结果生成svg矢量图;

    • 更多Heob参数使用命令行Heob64.exe -H查看。

    在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4、使用Heob分析qt 程序内存泄漏🦧

  1. 打开测试代码,使用MSVC编译器、Debug模式进行编译,保留pdb符号表;

  2. 编译生成可执行程序;

  3. 点击【分析】【Heob】【OK】启动程序进行分析;

  4. 当程序运行后分别点击【泄漏1】【泄漏2】按键,然后退出程序,程序退出后会将分析结果生成位leaks.xml文件,并在调试窗口显示检测到的内存泄漏;

  5. 生成的检测结果会有许多动态库中的误报,可以点击调试窗口上的过滤图标,取消勾选【外部错误】项(如果MSVC版本<=2017则勾选外部错误);

    在这里插入图片描述

  6. 检测结果如下所示,出现两个内存泄漏,大小分别是409600字节和16字节。

    在这里插入图片描述

    在这里插入图片描述

5、使用Heob检测qt 程序野指针/内存越界👓

  • 打开Heob窗口;
  • 将Page protection选为【After】或者【Before 】;
  • 点击开始检测,运行野指针代码就可以成功捕获到野指针异常。
  • 由于野指针、内存越界都是不可恢复的异常,所以检测到这类异常后会直接终止Heob。

在这里插入图片描述

6、使用Heob检测qt 程序空指针/throw抛出异常👕

  • 打开Heob窗口;
  • 使用默认设置;
  • 点击开始检测,运行野指针代码就可以成功捕获到空指针、抛出异常。
  • 由于空指针异常无法恢复,检测到后会终止Heob;
  • 如果throw抛出异常后没有被try捕获,则会被Heob检测到,并触发终止,如果被try捕获,则Heob无法检测。

在这里插入图片描述

7、使用Heob检测qt 程序重复释放👗

  • 打开Heob窗口;
  • 勾选Raise breakpoint exception on error: 表示出现异常时触发断点,如果不勾选就只会保存到检测结果;
  • 再勾选Run with debugger ,在出现重复释放异常时,就会触发断点,进入调试。

在这里插入图片描述

8、使用Heob检测qt 程序长生命周期式内存泄漏👙

这里的长生命周期式内存泄漏不同于普通内存泄漏使用new分配了而没有delete;

长生命周期内存泄漏指使用new分配了内存,过了很长时间才会delete,例如成员指针、全局变量、静态变量等;

这类内存泄漏会更加难以排查,也容易造成严重问题。

测试方法1: 无法检测到长生命周期内存泄漏

  • 打开Heob进行检测;
  • 点击按键,向成员数组中new大量变量;
  • 过一段时间后再释放成员数组中的所有内存;
  • 无法检测到出现内存泄漏;

在这里插入图片描述

测试方法1: 无法检测到长生命周期内存泄漏

  • 打开Heob窗口;

  • 如下图所示,选择Detect Leak Types(不必须),避免文件写入太多内存,检测大小设置为500字节(不必须),选择On(Start Disabled),在程序启动前不记录,在运行过程中通过终端命令行控制开始/结束记录的时机;

    在这里插入图片描述

  • 点击【OK】启动Heob;

  • 程序运行后按下n键开始记录;

  • 然后在程序中分别给成员数组、全局数组分配内存;

  • 在终端按下f键停止记录,并按下s键将当前内存泄漏分析结果写入文件

  • 然后点击按键释放数组分配的内存;

  • 退出程序后就可以看见检测到的内存泄漏了。

在这里插入图片描述

9、相关地址🐐

  • Heob
  • 下载dwarfstack.dll
  • 通过cv2pdb将DWARF 转成PDB
  • Heob | Qt Creator Documentation
  • Detect memory leaks with Heob | Qt Creator Documentation

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

uni-app快速入门(八)--常用内置组件(上)

uni-app提供了一套基础组件&#xff0c;类似HTML里的标签元素&#xff0c;不推荐在uni-app中使用使用div等HTML标签。在uni-app中&#xff0c;对应<div>的标签是view&#xff0c;对应<span>的是text&#xff0c;对应<a>的是navigator&#xff0c;常用uni-app…

静态时序分析--时序约束

目录 1.时钟约束1.1创建时钟1.2.生成时钟1.3虚拟时钟1.4 最小时钟脉宽 2.I/O延时约束2.1设置输入延时2.2设置输出延时 3.I/O环境建模约束3.1输入驱动建模3.2输出负载建模 4.时序例外4.1多周期路径设置&#xff08;multicycle path&#xff09;4.2伪路径设置&#xff08;false_p…

解决IntelliJ IDEA的Plugins无法访问Marketplace去下载插件

勾选Auto-detect proxy setting并填入 https://plugins.jetbrains.com 代理URL&#xff0c;可以先做检查连接&#xff1a;

自存 sql常见语句和实际应用

关于连表 查询两个表 SELECT * FROM study_article JOIN study_article_review 查询的就是两个表相乘&#xff0c;结果为两个表的笛卡尔积 相这样 这种并不是我们想要的结果 通常会添加一些查询条件 SELECT * FROM study_articleJOIN study_article_review ON study_art…

目录背景缺少vscode右键打开选项

目录背景缺少vscode右键打开选项 1.打开右键管理 下载地址&#xff1a;https://wwyz.lanzoul.com/iZy9G2fl28uj 2.开始搜索框搜索vscode&#xff0c; 找到其源目录 3.目录背景里面&#xff0c; 加入vscode.exe 3.然后在目录背景下&#xff0c; 右键&#xff0c; code就可以打…

应用于各种小家电的快充协议芯片

前言 随着快充技术的广泛应用&#xff0c;以往小家电的慢充模式已经满足不了人们对充电速度的要求&#xff0c;因此商家纷纷对小家电应用了诱骗取电快充协议芯片 例如&#xff08;XSP16H)&#xff0c;有了快充的支持小家电的充电速度有了很大的提升&#xff0c;节省了很多的充电…

Java基础知识(五)

文章目录 ObjectObject 类的常见方法有哪些&#xff1f; 和 equals() 的区别hashCode() 有什么用&#xff1f;为什么要有 hashCode&#xff1f;为什么重写 equals() 时必须重写 hashCode() 方法&#xff1f; 参考链接 Object Object 类的常见方法有哪些&#xff1f; Object 类…

【spring 】Spring Cloud Gateway 的Filter学习

介绍和使用场景 Spring Cloud Gateway 是一个基于 Spring Framework 5 和 Project Reactor 的 API 网关&#xff0c;它旨在为微服务架构提供一种简单而有效的方式来处理请求路由、过滤、限流等功能。在 Spring Cloud Gateway 中&#xff0c;Filter 扮演着非常重要的角色&#…

[Docker#11] 容器编排 | .yml | up | 实验: 部署WordPress

目录 1. 什么是 Docker Compose 生活案例 2. 为什么要使用 Docker Compose Docker Compose 的安装 Docker Compose 的功能 使用步骤 核心功能 Docker Compose 使用场景 Docker Compose 文件&#xff08;docker-compose.yml&#xff09; 模仿示例 文件基本结构及常见…

学习虚幻C++开发日志——委托(持续更新中)

委托 官方文档&#xff1a;Delegates and Lamba Functions in Unreal Engine | 虚幻引擎 5.5 文档 | Epic Developer Community | Epic Developer Community 简单地说&#xff0c;委托就像是一个“函数指针”&#xff0c;但它更加安全和灵活。它允许程序在运行时动态地调用不…

【Linux】基础02

Linux编译和调试 VI编辑文件 vi : 进入文件编辑 是命令行模式 i &#xff1a;从光标处进入插入模式 dd : 删除光标所在行 n dd 删除指定行数 Esc &#xff1a; 退出插入模式 &#xff1a; 冒号进入末行模式 :wq : 保存退出 :q &#xff1a; 未修改文件可以退出 :q! …

前端:JavaScript (学习笔记)【1】

目录​​​​​​​ 一&#xff0c;介绍JavaScript 二&#xff0c;JavaScript的特点 1&#xff0c;脚本语言 2&#xff0c;基于对象的语言 3&#xff0c;事件驱动 4&#xff0c;简单性 5&#xff0c;安全性 6&#xff0c;跨平台性 7&#xff0c;JS 和java的区别 &…

安卓手机root+magisk安装证书+抓取https请求

先讲一下有这篇文章的背景吧&#xff0c;在使用安卓手机fiddler抓包时&#xff0c;即使信任了证书&#xff0c;并且手机也安装了证书&#xff0c;但是还是无法捕获https请求的问题&#xff0c;最开始不知道原因&#xff0c;后来慢慢了解到现在有的app为了防止抓包&#xff0c;把…

数字化那点事:一文读懂物联网

一、物联网是什么&#xff1f; 物联网&#xff08;Internet of Things&#xff0c;简称IoT&#xff09;是指通过网络将各种物理设备连接起来&#xff0c;使它们可以互相通信并进行数据交换的技术系统。通过在物理对象中嵌入传感器、处理器、通信模块等硬件&#xff0c;IoT将“…

Tomcat和Nginx原理说明

Tomcat Tomcat 是一个开源的 Java 应用服务器&#xff0c;它由多个关键组件组成。这些组件共同协作&#xff0c;实现了 Servlet 容器的功能。以下是 Tomcat 的核心组件说明及其逻辑架构的示意图。 1. Tomcat 核心组件说明 (1) Server 描述&#xff1a;Tomcat 的顶级组件&…

【大模型】LLaMA: Open and Efficient Foundation Language Models

链接&#xff1a;https://arxiv.org/pdf/2302.13971 论文&#xff1a;LLaMA: Open and Efficient Foundation Language Models Introduction 规模和效果 7B to 65B&#xff0c;LLaMA-13B 超过 GPT-3 (175B)Motivation 如何最好地缩放特定训练计算预算的数据集和模型大小&…

一文解决Latex中的eps报错eps-converted-to.pdf not found: using draft setting.

在使用Vscode配的PDFLatex编译IEEE TII的Latex模板时&#xff0c;出现eps文件不能转换为pdf错误&#xff0c;看了几十篇方法都没用&#xff0c;自己研究了半天终于可以正常运行了。主要原因还是Settings.JSON中的PDFLatex模块缺少&#xff1a;"--shell-escape", 命令…

【流量分析】常见webshell流量分析

免责声明&#xff1a;本文仅作分享&#xff01; 对于常见的webshell工具&#xff0c;就要知攻善防&#xff1b;后门脚本的执行导致webshell的连接&#xff0c;对于默认的脚本要了解&#xff0c;才能更清晰&#xff0c;更方便应对。 &#xff08;这里仅针对部分后门代码进行流量…

Java前端基础——CSS

一、CSS介绍 1.1 什么是CSS CSS(Cascading Style Sheet)&#xff0c;层叠样式表,用于控制页面的样式. CSS 能够对网页中元素位置的排版进行像素级精确控制, 实现美化页面的效果. 能够做到页面的样式和结构分离. 1.2 基本语法规范 选择器 {⼀条/N条声明} • 选择器决定针…

游戏引擎学习第17天

视频参考:https://www.bilibili.com/video/BV1LPUpYJEXE/ 回顾上一天的内容 1. 整体目标&#xff1a; 处理键盘输入&#xff1a;将键盘输入的处理逻辑从平台特定的代码中分离出来&#xff0c;放入更独立的函数中以便管理。优化消息循环&#xff1a;确保消息循环能够有效处理 …