使用`LD_PRELOAD`和`jemalloc`实现C/C++信号的内存堆栈信息收集

文章目录

    • 0. 概要
    • 1. 编译jemalloc
    • 2. 编译钩子共享库liballoc_hook.so
    • 3. 使用`LD_PRELOAD`加载钩子库liballoc_hook.so测试
      • 3.1 设置环境变量
      • 3.2 使用`LD_PRELOAD`加载钩子库并运行程序
      • 3.3 发送`SIGUSR1`信号以触发堆栈信息打印
      • 3.4 使用jeprof解析heap堆栈信息文件
    • 4. 示例程序example.cpp代码
    • 5. 注意事项
    • 6. jemalloc的限制

0. 概要

本文介绍如何结合LD_PRELOADjemalloc,在接收到SIGUSR1信号时打印程序的堆栈信息。详细步骤包括编译和配置jemalloc,编写信号处理程序,并通过LD_PRELOAD加载共享库的方法。

1. 编译jemalloc

编译并安装启用prof功能的jemalloc。以下是Ubuntu 18.04上的编译步骤:

git clone https://github.com/jemalloc/jemalloc.git  # 本文测试的版本是jemalloc-5.3.0
cd jemalloc
./configure --prefix=/usr/local --enable-prof CFLAGS="-fPIC"
make -j10
sudo make install

确保编译 libjemalloc.a 时使用了 -fPIC 选项。

2. 编译钩子共享库liballoc_hook.so

创建一个名为alloc_hook.c的文件,并实现信号处理函数:

/*gcc -o liballoc_hook.so -shared -fPIC alloc_hook.c -Wl,-Bstatic -ljemalloc -Wl,-Bdynamic
*/
#include <jemalloc/jemalloc.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>// 信号处理函数
void handle_signal(int signum) {if (signum == SIGUSR1) {// 触发 jemalloc 的 heap profiling dumpmallctl("prof.dump", NULL, NULL, NULL, 0);printf("Heap profile dump generated.\n");}
}// 初始化函数
void __attribute__((constructor)) init_hook() {// 设置信号处理函数signal(SIGUSR1, handle_signal);printf("Signal handler for SIGUSR1 is set.\n");
}

使用以下命令编译liballoc_hook.so并静态链接libjemalloc.a

gcc -o liballoc_hook.so -shared -fPIC alloc_hook.c -Wl,-Bstatic -ljemalloc -Wl,-Bdynamic -lpthread

3. 使用LD_PRELOAD加载钩子库liballoc_hook.so测试

假设你的目标程序是example,通过LD_PRELOAD加载liballoc_hook.so钩子库,按照以下步骤运行和测试:

3.1 设置环境变量

export MALLOC_CONF="prof:true,prof_active:true,lg_prof_sample:0,tcache:false,prof_prefix:jeprof.out"
  • prof:true:启用配置文件。
  • prof_active:true:启用性能分析。
  • lg_prof_sample:0:设置采样率为最高。
  • tcache:false:禁用线程缓存,可能影响性能,但在进行性能分析时,可以提供更准确的内存分配数据。
  • prof_prefix:jeprof.out:指定性能分析输出文件前缀。

3.2 使用LD_PRELOAD加载钩子库并运行程序

LD_PRELOAD="/path/to/liballoc_hook.so" ./example

3.3 发送SIGUSR1信号以触发堆栈信息打印

killall -10 example 
# 或者
killall -SIGUSR1 example

通过以上步骤,你可以在接收到SIGUSR1信号时打印jemalloc的堆栈信息,并将其输出到本地目录。本文得到的堆栈信息文件名为jeprof.out.60571.0.m0.heap

3.4 使用jeprof解析heap堆栈信息文件

通过如下命令分析该堆栈信息文件:

jeprof --show_bytes --text --lines ./example ./jeprof.out.60571.0.m0.heap

解析结果示例如下:

$ jeprof --show_bytes --text --lines ./example jeprof.out.60571.0.m0.heap 
Using local file ./example.
Using local file jeprof.out.60571.0.m0.heap.
Total: 83512 B82944  99.3%  99.3%    82944  99.3% prof_backtrace_impl /tmp/jemalloc-5.3.0/src/prof_sys.c:103448   0.5%  99.9%      448   0.5% allocateIntArray /home/test/jemalloc_test/example.cpp:1380   0.1% 100.0%       80   0.1% allocateDynamicArray /home/test/jemalloc_test/example.cpp:32 (discriminator 1)32   0.0% 100.0%       32   0.0% allocateString /home/test/jemalloc_test/example.cpp:258   0.0% 100.0%        8   0.0% allocateDouble /home/test/jemalloc_test/example.cpp:190   0.0% 100.0%     1024   1.2% _IO_new_file_overflow /build/glibc-2ORdQG/glibc-2.27/libio/fileops.c:7590   0.0% 100.0%     1024   1.2% _IO_new_file_xsputn /build/glibc-2ORdQG/glibc-2.27/libio/fileops.c:12660   0.0% 100.0%     1024   1.2% _IO_puts /build/glibc-2ORdQG/glibc-2.27/libio/ioputs.c:400   0.0% 100.0%     1024   1.2% __GI__IO_doallocbuf /build/glibc-2ORdQG/glibc-2.27/libio/genops.c:3650   0.0% 100.0%     1024   1.2% __GI__IO_file_doallocate /build/glibc-2ORdQG/glibc-2.27/libio/filedoalloc.c:1010   0.0% 100.0%      568   0.7% __libc_start_main /build/glibc-2ORdQG/glibc-2.27/csu/../csu/libc-start.c:3100   0.0% 100.0%    82944  99.3% _dl_start_user :?0   0.0% 100.0%      568   0.7% _start ??:?0   0.0% 100.0%      448   0.5% allocateMemory /home/test/jemalloc_test/example.cpp:510   0.0% 100.0%        8   0.0% allocateMemory /home/test/jemalloc_test/example.cpp:520   0.0% 100.0%       32   0.0% allocateMemory /home/test/jemalloc_test/example.cpp:530   0.0% 100.0%       80   0.1% allocateMemory /home/test/jemalloc_test/example.cpp:540   0.0% 100.0%    82944  99.3% call_init /build/glibc-2ORdQG/glibc-2.27/elf/dl-init.c:720   0.0% 100.0%    82944  99.3% imalloc (inline) /tmp/jemalloc-5.3.0/src/jemalloc.c:26940   0.0% 100.0%    82944  99.3% imalloc_body (inline) /tmp/jemalloc-5.3.0/src/jemalloc.c:25500   0.0% 100.0%     1024   1.2% init_hook ??:?0   0.0% 100.0%    82944  99.3% je_malloc_default /tmp/jemalloc-5.3.0/src/jemalloc.c:27220   0.0% 100.0%    82944  99.3%je_prof_backtrace /tmp/jemalloc-5.3.0/src/prof_sys.c:2840   0.0% 100.0%    82944  99.3% je_prof_tctx_create /tmp/jemalloc-5.3.0/src/prof.c:1950   0.0% 100.0%      568   0.7% main /home/test/jemalloc_test/example.cpp:600   0.0% 100.0%    82944  99.3% prof_alloc_prep (inline) /tmp/jemalloc-5.3.0/include/jemalloc/internal/prof_inlines.h:1410   0.0% 100.0%    81920  98.1% std::__once_callable ??:0

4. 示例程序example.cpp代码

以下是完整的example.cpp代码,编译方法: g++ -g -o example example.cpp

#include <sys/mman.h>           // mmap, munmap
#include <unistd.h>             // usleep
#include <csignal>              // signal, sigaction
#include <cstdlib>              // rand()和srand()
#include <ctime>                // time()
#include <iostream>
#include <string>
#include <vector>// 分配int数组
void allocateIntArray() {const int* intPtr = new int[100];std::cout << "Allocated int array at: " << intPtr << std::endl;
}// 分配double
void allocateDouble() {const double* doublePtr = new double(3.14);std::cout << "Allocated double at: " << doublePtr << ", value: " << *doublePtr << std::endl;
}// 分配字符串
void allocateString() {const std::string* strPtr = new std::string("Hello, World!");std::cout << "Allocated string at: " << strPtr << ", value: " << *strPtr << std::endl;
}// 分配动态数组
void allocateDynamicArray() {size_t arraySize = 10;size_t* const arrayPtr = new size_t[arraySize];std::cout << "Allocated array of " << arraySize << " ints at: " << arrayPtr << std::endl;for (size_t i = 0; i < arraySize; ++i) {arrayPtr[i] = i;}
}// 使用mmap分配内存
void allocateMmap() {size_t mmapSize = 4096;  // 4KBconst void* mmapPtr = mmap(nullptr, mmapSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);if (mmapPtr == MAP_FAILED) {perror("mmap failed");} else {std::cout << "Allocated mmap at: " << mmapPtr << ", size: " << mmapSize << " bytes" << std::endl;}
}void allocateMemory() {allocateIntArray();allocateDouble();allocateString();allocateDynamicArray();allocateMmap();
}int main() {usleep(100000);  // 100msallocateMemory();while (true) {usleep(100000);  // 100ms}return 0;
}

5. 注意事项

  • 编译libjemalloc.a时请记得添加CFLAGS="-fPIC"

    ./configure --prefix=/usr/local --enable-prof CFLAGS="-fPIC"
    
  • liballoc_hook.so必须是静态链接libjemalloc.a

  • liballoc_hook.so需要动态链接libpthread.so,编译时记得切回动态链接方式:

    gcc -o liballoc_hook.so -shared -fPIC alloc_hook.c -Wl,-Bstatic -ljemalloc -Wl,-Bdynamic -lpthread
    
  • 请勿使用动态加载libjemalloc.so。如果使用如下命令:

    LD_PRELOAD="/path/to/liballoc_hook.so /usr/local/lib/libjemalloc.so" ./example
    

jeprof解析heap的结果会显示为:

$ jeprof --show_bytes --text --lines ./example ./jeprof.out.60571.0.m0.heap 
Using local file ./example.
Using local file ./jeprof.out.60571.0.m0.heap.
Total: 83512 B83512 100.0% 100.0%    83512 100.0% prof_backtrace_impl /tmp/jemalloc-5.3.0/src/prof_sys.c:1030   0.0% 100.0%      568   0.7% 0x00005610af62de49 ??:00   0.0% 100.0%      448   0.5% 0x00005610af62df3b ??:00   0.0% 100.0%        8   0.0% 0x00005610af62df8e ??:00   0.0% 100.0%       32   0.0% 0x00005610af62e039 ??:00   0.0% 100.0%       80   0.1% 0x00005610af62e137 ??:00   0.0% 100.0%      448   0.5% 0x00005610af62e299 ??:00   0.0% 100.0%        8   0.0% 0x00005610af62e29e ??:00   0.0% 100.0%       32   0.0% 0x00005610af62e2a3 ??:00   0.0% 100.0%       80   0.1% 0x00005610af62e2a8 ??:00   0.0% 100.0%      568   0.7% 0x00005610af62e2c3 ??:0

可以看到example.cpp部分的信息无法显示,因此不可使用LD_PRELOAD同时加载liballoc_hook.solibjemalloc.so

6. jemalloc的限制

尽管jemalloc在内存管理和性能分析方面具有强大的功能,但它也存在一些限制:

  • 无法hook mmap
    jemalloc无法hook通过mmapmunmap进行的内存分配。这意味着如果程序中大量使用mmap进行内存分配,这部分内存不会被jemalloc监控和管理,也不会包含在jemalloc的内存分析报告中。因此,对于需要分析这种内存分配行为的程序,jemalloc可能不是最佳选择。

  • 无法hook线程相关信息
    jemalloc无法直接监控线程的创建和销毁。这对于某些需要详细分析线程行为的应用程序来说是一个限制。尽管jemalloc可以通过配置和编译选项优化内存分配以适应多线程环境,但它不能提供与线程操作相关的详细信息。

  • 无法hook直接系统调用的内存分配
    如果程序通过直接系统调用(如brk或其他系统级内存分配调用)分配内存,这些调用将绕过jemalloc的内存管理机制。因此,jemalloc无法跟踪这些内存分配行为,导致分析结果不完整。

  • 高采样率对性能的影响
    开启高采样率(如lg_prof_sample:0)会显著影响程序的性能。虽然高采样率能够提供更详细和频繁的内存分配数据,但它也会导致程序运行速度变慢。因此,在生产环境中需要权衡采样率和性能之间的关系。

  • 配置和使用复杂度
    正确配置和使用jemalloc需要一定的专业知识和经验。对于不熟悉内存管理和性能分析的开发者来说,jemalloc的配置选项和参数可能显得复杂,容易出错。因此,在使用jemalloc进行内存分析之前,建议详细阅读官方文档并进行充分测试。

  • 与其他内存管理库的兼容性问题
    在某些情况下,jemalloc可能与其他内存管理库或工具产生兼容性问题。这可能导致程序在链接和运行时遇到问题。因此,在将jemalloc集成到现有项目时,需要进行全面的测试以确保兼容性。

总的来说,尽管jemalloc是一款功能强大的内存管理库,但在使用过程中需要注意其自身的限制,并根据具体需求进行权衡和取舍。

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

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

相关文章

详细说说机器学习在医疗领域的应用

机器学习在医疗领域的应用广泛而深入&#xff0c;为医疗行业带来了显著的变革。以下是机器学习在医疗领域的主要应用方面&#xff1a; 个性化治疗&#xff1a; 机器学习能够根据病人的个体差异和基因组信息&#xff0c;帮助医生制定个性化的治疗方案。通过分析大规模的基因组数…

探地雷达正演模拟,基于时域有限差分方法,一

声明&#xff1a;本博客中的公式均是在Word中使用AxMath写好后截图使用的&#xff0c;欢迎引用&#xff0c;但请标注来源。 本系列会有四篇博客&#xff1a; 第一篇内容&#xff1a; 1、基础知识掌握 2、Maxwell方法差分求解原理 第二篇内容&#xff1a; 1、基于C的TE波波…

docker——基础知识

简介 一、什么是虚拟化和容器化 ​ 实体计算机叫做物理机&#xff0c;又时也称为寄主机&#xff1b; ​ 虚拟化&#xff1a;将一台计算机虚拟化为多态逻辑计算机&#xff1b; ​ 容器化&#xff1a;一种虚拟化技术&#xff0c;操作系统的虚拟化&#xff1b;将用户空间软件实…

mongodb总概

一、mongodb概述 mongodb是最流行的nosql数据库&#xff0c;由C语言编写。其功能非常丰富&#xff0c;包括: 面向集合文档的存储:适合存储Bson(json的扩展)形式的数据;格式自由&#xff0c;数据格式不固定&#xff0c;生产环境下修改结构都可以不影响程序运行;强大的查询语句…

2 程序的灵魂—算法-2.2 简单算法举例-【例 2.3】

【例 2.3】判定 2000 — 2500 年中的每一年是否闰年&#xff0c;将结果输出。 润年的条件: 1. 能被 4 整除&#xff0c;但不能被 100 整除的年份&#xff1b; 2. 能被 100 整除&#xff0c;又能被 400 整除的年份&#xff1b; 设 y 为被检测的年份&#xff0c;则算法可表示如下…

Element-UI全面入门与实战技巧

本文详细介绍了Element-UI的安装、配置、组件使用、布局技巧、交互设计、表单处理、主题定制等内容&#xff0c;旨在帮助开发者快速掌握Element-UI&#xff0c;并能在实际项目中灵活应用。 文章目录 一、Element-UI概述与安装1.1 Element-UI简介1.2 环境搭建1.3 安装Element-UI…

C语言:定义和使用结构体变量

定义和使用结构体变量 介绍基础用法1.定义结构体2. 声明结构体变量3. 初始化和访问结构体成员4. 使用指针访问结构体成员5. 使用结构体数组 高级用法6. 嵌套结构体7. 匿名结构体8. 结构体和动态内存分配9. 结构体作为函数参数按值传递按引用传递 介绍 在C语言中&#xff0c;结…

Edge怎么关闭快捷键

Edge怎么关闭快捷键 在Edge浏览器中&#xff0c;你可以通过以下步骤关闭快捷键&#xff1a; 打开Edge浏览器&#xff0c;输入&#xff1a;edge://flags 并按下回车键。 在Flags页面中&#xff0c;搜索“快捷键”(Keyboard shortcuts)选项。 将“快捷键”选项的状态设置为“…

Python 基于鲁棒核迭代最近点算法的点云精配准[Robust_ICP算法]

点云配准鲁棒迭代最近点算法 一、概述1.1 定义1.2 算法步骤二、代码示例三、运行结果一、概述 1.1 定义 Robust_ICP(鲁棒迭代最近点算法):是一种改进的ICP(Iterative Closest Point)算法,用于处理3D点云配准问题,特别是在存在噪声、外点(不匹配点)或数据分布不均等复杂…

dos命令---根据端口查找进程

简介 在日常开发中&#xff0c;常常出现端口被占用的情况&#xff0c;导致程序运行报错&#xff0c;这时可以使用此命令查看哪个进程占用了端口 命令 netstat -ano | findstr 11434返回结果&#xff1a;

关于利用hashcat破解WiFi数据包的操作记录

准备数据包相关转换工具 ┌──(kali㉿kali)-[~/cap/3204] └─$ sudo apt-cache search hc | grep ^hc hcloud-cli - command-line interface for Hetzner Cloud hcxdumptool - Small tool to capture packets from wlan devices hcxkeys - Tools to generate plainmasterkey…

【简单介绍下DALL-E2,什么是DALL-E2?】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

【代码随想录算法训练营第37期 第三十二天 | LeetCode122.买卖股票的最佳时机II、55. 跳跃游戏、45.跳跃游戏II】

代码随想录算法训练营第37期 第三十二天 | LeetCode122.买卖股票的最佳时机II、55. 跳跃游戏、45.跳跃游戏II 一、122.买卖股票的最佳时机II 解题代码C&#xff1a; class Solution { public:int maxProfit(vector<int>& prices) {int result 0;for(int i 1; i &…

10.爬虫---XPath插件安装并解析爬取数据

10.XPath插件安装并解析爬取数据 1.XPath简介2.XPath helper安装3.XPath 常用规则4.实例引入4.1 //匹配所有节点4.2 / 或 // 匹配子节点或子孙节点4.3 ..或 parent::匹配父节点4.4 匹配属性4.5 text()文本获取4.6 属性获取4.7 属性多值匹配 1.XPath简介 XPath是一门在XML文档中…

46-3 护网溯源 - 溯源报告编写

格式 1. 基本情况︰钓鱼邮件情况介绍 在这部分,需要详细描述钓鱼邮件的基本情况,包括收到的邮件内容、寄件人信息、邮件附件或链接等。还需说明收到邮件的时间和频率。2. 行为分析 详细阐述攻击者的行为模式和攻击方式,包括攻击手段、使用的恶意工具或技术,以及可能的入侵…

Flutter旅游出行类APP常用的第三方库总汇

Flutter旅游出行类APP常用的第三方库总汇 旅游出行类APP为用户提供了探索世界、规划旅程和预订服务的便捷方式。Flutter作为一个流行的跨平台移动应用开发框架&#xff0c;为这类应用的开发提供了强大的支持。本文将汇总Flutter旅游出行类APP开发中常用的第三方库&#xff0c;…

Spring - springfox-spi knife4j 版本冲突解决方案

问题描述 An attempt was made to call a method that does not exist. The attempt was made from the following location: com.github.xiaoymin.knife4j.spring.plugin.OperationDynamicResponseModelProvider.apply(OperationDynamicResponseModelProvider.java:47) The f…

Matlab|混合策略改进的蝴蝶优化算法

目录 1 主要内容 2 部分代码 3 程序结果 4 下载链接 1 主要内容 程序主要对蝴蝶算法&#xff08;BOA&#xff09;进行改进&#xff0c;参考文献《基于改进蝴蝶优化算法的冗余机器人逆运动学求解》&#xff0c;有如下改进策略&#xff1a; 改进1&#xff1a;采用反向学习策…

手把手带你做一个自己的网络调试助手(1) - TCP服务器准备

程序设计流程图 TCP 服务器 ui界面搭建 Tcp服务器建立连接 - listen() connect() 1.在构造函数中进行如下初始化: 通过 QNetworkInterface 类的 allAddresses 这一API 获得可用IP地址&#xff08;包括IPv4 和 IPv6&#xff09; 然后通过QHostAddress类的 protocol 这一AP…

C++,观察者模式,模拟Qt的信号和槽机制

运行在VS2022&#xff0c;x86&#xff0c;Debug下 33. 模拟Qt信号和槽机制 信号与槽实现原理&#xff1a;观察者模式&#xff0c;即当一个对象被修改时&#xff0c;就会自动通知依赖它的对象。应用&#xff1a;对象间的通信。Qt实现信号与槽&#xff0c;代码如下。 #include…