C++内存使用统计工具(Valgrind之massif)

应用场景

应用程序运行一段时间后,内存确实在增长,使用valgrind的memcheck工具检测出来,确实没有出现definitely lostindirectly lost两种类型的内存泄漏的情况。但是,细心的小伙伴会发现
still reachable类型的内存一直在增长,比如内存泄漏检测工具之memcheck无法检测的场景。我们有没有办法得知这个内存在哪里增长的呢?答案是,肯定有办法,那就是本章节介绍的重点valgrind之massif工具

工具使用局限性

  • 只能检测程序运行过的流程中的内存资源申请使用统计,未运行的流程分支,都无法统计。因为未运行,就不涉及内存的申请与释放。因此,需要覆盖完全的话,则需要覆盖所有的分支和流程。
  • 仅支持程序的正常退出和信号为SIGINT(ctrl+c)的程序退出,不支持kill -9程序的操作

工具安装

通过massif工具检测出来的报告,可以通过valgrind自带的ms_print工具打印出来查看,可视化效果不是很好,大家后续可以直观感受一下,本文将不再介绍。现在我们介绍安装一款可视化效果好一点的工具massif-visualizer

安装massif-visualizer

局限性

此款工具仅有Linux版本,没有Windows版本。如果没有Linux系统,那就只能将就使用valgrind自带的ms_print工具查看。

配置镜像源

直接连接国外服务器下载相关的软件,网速非常慢,甚至无法连接。可参考WSL+Ubuntu环境搭建之配置Ubuntu源

工具安装
在Linux命令行中执行如下命令即可:

sudo apt update
sudo apt install massif-visualizer

检查安装结果

命令:

massif-visualizer --version

输出:

massif-visualizer 0.7

WSL2安装远程桌面和图形化界面

如果读者使用的是Windows+WSL2的场景,那么就需要安装支持远程桌面和图形化界面的软件包。不同的Linux操作系统可能有不同的解决方案,笔者使用的是ubuntu20.04,那就以ubuntu20.04为例。

其实,在安装好massif-visualizer工具,直接执行时,会报告以下错误:

qt.qpa.xcb: could not connect to display
qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found.
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.

Available platform plugins are: eglfs, linuxfb, minimal, minimalegl, offscreen, vnc, wayland-egl, wayland, wayland-xcomposite-egl, wayland-xcomposite-glx, xcb.

Qt图形化的支持非常友好,此处报告缺乏Qt的插件,说明缺乏图形化的界面软件。

安装远程桌面

sudo apt install xrdp

sudo sed -i 's/port=3389/port=3390/g' /etc/xrdp/xrdp.ini  # 将远程桌面端口修改为3390

sudo echo xfce4-session >~/.xsession

sudo service xrdp start  # 每次需要远程连接时,需要执行的命令,可在网上查找设置成自启动命名

轻量级的图形化界面

sudo apt install xfce4

验证安装结果

  • 在Windows,启动远程桌面连接应用程序。
  • 计算机输入栏,输入:localhost:3390用户名输入栏,输入:ubuntu20.04的用户命名;弹出的界面中,输入相应的密码。

如果成功的进入如下界面,就算安装成功了:

在这里插入图片描述

工具使用

valgrind之massif工具

使用massif工具统计出内存使用的信息。其中Xxxx是可执行程序的文件名

valgrind --tool=massif --time-unit=ms ./Xxxx

注:如果程序是长时间持续运行的,可考虑终端命令行中,向该进程发送SIGINT(ctrl+c)信号。

输出文件:massif.out.1132,其中1132是进程编号。这是一个文本文件。

massif-visualizer工具使用

前提: 如果使用的是WSL2,则需要使用远程桌面连接应用程序,连接WSL2的桌面。

在Ubuntu的远程桌面命令行中,执行如下命令:

massif-visualizer massif.out.1132

即可弹出相应的图形化界面。

内存统计场景举例

此处,主要针对内存泄漏检测工具之memcheck无法检测的场景的几种场景进行分析。

申请内存在同一个上下文

代码示例:

为了更加直观,将申请的元素个数变更:10->10240.

#include <thread>
#include <chrono>
using namespace std;

int main()
{
    int* ptr = new int[10240]();

    return 0;
}

通过工具使用章节,运行后的结果如下:

在这里插入图片描述

从上图,可以看出:

  • 黄色部分,是程序加载时的内存占用
  • 蓝色部分,在main函数中,占用了40KB的内存

结论:10240个4字节的元素,刚好为40KB的内存空间,与预期相符。

容器或者缓存一直增长

代码示例:

#include <cstdint>
#include <thread>
#include <chrono>
#include <vector>

using namespace std;

vector<uint32_t> g_memPool;

void Fun(uint32_t num)
{
    g_memPool.push_back(num);
}

int32_t main()
{
    for (uint8_t i = 0; i < 256; ++i) {
        Fun(i);
        this_thread::sleep_for(chrono::milliseconds(1));   // 我们为了统计结果更直观,此处将延时改为1ms
    }

    return 0;
}

通过工具使用章节,运行后的结果如下:

在这里插入图片描述

通过上图,可以看到:

  • 橘色部分的内存一直在增长,而且对应内存增长的地方,就是我们应用程序中的g_memPool.push_back(num);部分的代码。
  • 绿色部分的内存,是程序启动加载时的内存占用,不涉及内存泄漏。

因此,可以很快的定位出来内存膨胀的原因了。

解决方案

将上述程序中导致死循环的的256->255后,再次运行程序,结果如下:

在这里插入图片描述

继续前行

问题:从上述程序来看,存储了255个4字节的数据,占用空间约1KB的内存,为何占用了1.5KB的内存呢?
原因:vector容器,在存储数据时,内存空间不足,则需要申请当前内存的2倍空间,并将数据拷贝到新的内存空间中。
解决方案:若提前知道需要存储的数据个数,可考虑一次直接预留足够的存储空间。

#include <cstdint>
#include <thread>
#include <chrono>
#include <vector>

using namespace std;

vector<uint32_t> g_memPool;

void Fun(uint32_t num)
{
    g_memPool.push_back(num);
}

int32_t main()
{
    g_memPool.reserve(255);
    for (uint8_t i = 0; i < 255; ++i) {
        Fun(i);
    }

    return 0;
}

运行结果如下:

在这里插入图片描述

从上述结果来看,vector容器所管理的内存空间,与期望结果相符。

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用Valgrind工具的Callgrind子工具统计所有申请内存的代码点。Callgrind是一款用于分析程序的CPU使用情况和函数调用关系的工具,它可以生成一个函数调用图和函数执行时间的详细报告。 要使用Callgrind来统计申请内存的代码点,可以按照以下步骤操作: 1. 安装Valgrind工具和Callgrind子工具。 2. 运行程序,并使用Valgrind和Callgrind工具来收集分析数据。可以使用以下命令: ``` valgrind --tool=callgrind ./my_program ``` 这会在当前目录下生成一个名为callgrind.out.pid的文件,其中pid是进程的ID号。 3. 使用Callgrind自带的工具kcachegrind来可视化分析数据。可以使用以下命令: ``` kcachegrind callgrind.out.pid ``` 这会打开一个图形界面,其中包含了程序的函数调用图和内存使用情况的详细报告。 在kcachegrind中,可以点击“内存”标签来查看程序中所有申请内存的代码点。这个列表会显示每个代码点的内存申请次数、申请的内存大小、以及调用此代码点的函数。可以根据这个列表来确定程序中哪些代码点申请了过多的内存,或者是哪些代码点导致了内存泄漏问题。 注意,使用Callgrind来统计所有申请内存的代码点会产生大量的分析数据,因此可能需要更多的时间和计算资源。另外,为了获得更准确的数据,建议在程序中加入尽可能多的测试用例和场景,以覆盖程序的全部功能和代码路径。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值