TDengine 研发分享:利用 Windbg 解决内存泄漏问题的实践和经验

内存泄漏是一种常见的问题,它会导致程序的内存占用逐渐增加,最终导致系统资源耗尽或程序崩溃。AddressSanitizer (ASan) 和 Valgrind 是很好的内存检测工具,TDengine 的 CI 过程就使用了 ASan 。不过这次内存泄漏问题发生在 Windows 下,我们 CI 暂时还没有覆盖到,因此 TDengine 研发选择使用 Windbg 来解决问题。结果证明,在 Windows 下,使用 Windbg 也是一个不错的选择。

内存泄漏的常用检测方法

内存泄漏通常会发生在以下情况下:

  • 程序未正确释放已分配的内存
  • 程序中存在循环引用,导致垃圾收集器无法回收内存
  • 程序中存在内存泄漏的第三方库或组件

内存泄漏的检测方法主要包括以下几种:

  1. 静态代码分析工具:未释放的指针或内存分配错误等问题,不能检测在程序运行时动态分配内存的情况。
  2. 动态分析工具:可以使用内存分配和释放跟踪器来跟踪程序中的内存分配和释放操作,并检测是否存在内存泄漏的情况。然而,使用某些工具(如Valgrind)可能会对程序的性能产生一定的影响。
  3. 调试器:WinDbg 和 GDB。

优缺点:

  • 静态代码分析工具可以在早期发现问题,但是它们不能检测程序运行时动态分配内存的情况。
  • 动态分析工具可以在程序运行时检测问题,但是它们可能会影响程序性能,并且在检测大型应用程序时可能需要大量的时间和资源。不过在资源充足的测试环境中跑的话,就都不是问题了,比如 ASan 就帮我们发现过不少问题。
  • 调试器可以在程序运行时检测问题,并提供强大的分析工具。

实践分析

基本原理

使用 Windbg 定位内存泄露,依赖 glags 组件记录程序在运行期间所有申请和释放的内存,同时记录的还有申请内存时的调用栈信息。这样在程序运行期间,使用 umdh 组件进行两次快照记录,通过比较两次快照信息的差异,就可以发现两次快照间隔时间段中申请却并未释放的内存申请信息。如果有内存泄露,diff 结果最前边一般就是泄漏点的调用栈信息。当然,两次快照期间,要尽量触发内存泄露,才能更准确的定位。diff 结果中还会有少量正常的申请没来得及释放的调用信息,不过 diff 结果中能看到调用次数,比较容易甄别。

问题介绍

taosdump 在 windows 导入数据出错:

build and install latest TDengine 3.0 branch on Windows
use "taosBenchmark -I stmt -y" to create a lot of tables and data (10000 * 10000).
use "taosdump -D test -o outputFile" to dump out
use "taos -s 'drop database test'" to drop database
use "taosdump -i inputFile" to dump in.

错误日志:taosd “tsem_init failed, errno: 28”

Taosdump: dumpInAvroDataImpl() LN7039 taos_stmt_execute() failed! reason: Out of Memory, timestamp: 1500000009256

定位过程

配置 gflags

gflags 工具应该位于路径:C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\gflags,如果没有的话,可以直接前往 Microsoft 的官方网站下载安装:Windows 调试工具 - Windows drivers | Microsoft Learn

安装完成后,在命令行执行 gflags.exe /i your_application.exe 可设置跟踪目标,同时可以设置相关参数。双击运行也是可以的,Image File 对应 /i 参数,选择启动程序 your_application.exe 后先按 tab 键,然后选择其他配置。

内存泄漏治理实战:TDengine 研发团队使用 Windbg 的经验分享 - TDengine Database 时序数据库

定位步骤

1. 启动 your_application.exe(我要调试的是 taosdump.exe,所以下边是 taosdump.exe)

“C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\gflags” -i taosdump.exe +ust

2. 拷贝 pdb 文件到 mysymbols 目录,pdb 文件存储了编译后的程序的调试信息,和可执行程序一起生成,可以在应用程序生成目录中找到。

3. Set pdb 目录

set _NT_SYMBOL_PATH=c:\mysymbols;srv*c:\mycache*https://msdl.microsoft.com/download/symbols

4. 生成第一次内存快照

"C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\umdh" -pn:taosdump.exe -f:C:\xstest\umdhlog\taosdump11.log

5. 生成第二次内存快照

"C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\umdh" -pn:taosdump.exe -f:C:\xstest\umdhlog\taosdump12.log

6. 生成快照比较结果(umdh)

"C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\umdh" C:\xstest\umdhlog\taosdump11.log C:\xstest\umdhlog\taosdump12.log -f:C:\xstest\umdhlog\taosdumpdiff11_12.log

分析与解决

结果文件

因为 taosdump 程序启动后直至退出都在做大量的业务工作,内存泄露很容易发生在两次快照期间。 988040 – 6ecf0 表示”申请次数 – 释放次数”, 很明显发生了内存泄露,泄漏点在 buildRequest 函数的 sem_init 这里。

+  919350 ( 988040 - 6ecf0)  201b0 allocs        BackTrace9CB6973F
+   1ea5c ( 201b0 -  1754)        BackTrace9CB6973F        allocations

        ntdll!RtlpAllocateHeapInternal+948D5
        taos!heap_alloc_dbg_internal+1F6 (minkernel\crts\ucrt\src\appcrt\heap\debug_heap.cpp, 359)
        taos!heap_alloc_dbg+4D (minkernel\crts\ucrt\src\appcrt\heap\debug_heap.cpp, 450)
        taos!_calloc_dbg+6C (minkernel\crts\ucrt\src\appcrt\heap\debug_heap.cpp, 518)
        taos!calloc+2E (minkernel\crts\ucrt\src\appcrt\heap\calloc.cpp, 30)
        taos!sem_init+5D (C:\workroom\TDengine\contrib\pthread\sem_init.c, 109)
        taos!buildRequest+209 (C:\workroom\TDengine\source\client\src\clientImpl.c, 192)
        taos!stmtCreateRequest+73 (C:\workroom\TDengine\source\client\src\clientStmt.c, 15)
        taos!stmtSetTbName+115 (C:\workroom\TDengine\source\client\src\clientStmt.c, 588)
        taos!taos_stmt_set_tbname+7F (C:\workroom\TDengine\source\client\src\clientMain.c, 1350)
        taosdump!dumpInAvroDataImpl+E25 (C:\workroom\TDengine\tools\taos-tools\src\taosdump.c, 6260)
        taosdump!dumpInOneAvroFile+3D2 (C:\workroom\TDengine\tools\taos-tools\src\taosdump.c, 7229)
        taosdump!dumpInAvroWorkThreadFp+20B (C:\workroom\TDengine\tools\taos-tools\src\taosdump.c, 7306)
        taosdump!ptw32_threadStart+CD (C:\workroom\TDengine\contrib\pthread\ptw32_threadStart.c, 233)
        taosdump!thread_start<unsigned int (__cdecl*)(void *),1>+9C (minkernel\crts\ucrt\src\appcrt\startup\thread.cpp, 97)
        KERNEL32!BaseThreadInitThunk+10
        ntdll!RtlUserThreadStart+2B
泄漏点修改

接下来查看代码并修改,C 语言对内存的使用自由度很高,因此也比较麻烦。可以看到有些路径遗漏了 tsem_destory 的调用。

内存泄漏治理实战:TDengine 研发团队使用 Windbg 的经验分享 - TDengine Database 时序数据库

更加详细的代码方案请见 Fix/xsren/td 21762/sem mem leak by facetosea · Pull Request #19580 · taosdata/TDengine · GitHub

总结

工欲善其事必先利其器,掌握更多的工具和手段,在解决问题时才能比较从容,Windbg 定位内存泄漏的方式非常简单,但是很有效。不过需要注意,它依赖 pdb 文件,因此,发布应用程序时要记得保留 pdb 文件。pdb 文件包含了程序的符号信息,能够帮助我们在调试过程中准确定位问题所在。

另外,从出问题的代码可以看出,这块内存的管理方式还是比较容易出错,RAII 机制能较好的避免资源泄露,C 语言中也可以通过模拟 RAII 来达到类似的效果,虽然没有 C++ 那么流畅,也许以后可以考虑优化一下。

RAII(Resource Acquisition Is Initialization)机制是一种重要的资源管理方式,它将资源的获取和对象的生命周期关联起来。通过在对象的构造函数中获取资源,在析构函数中释放资源,我们可以确保资源的正确管理,防止资源泄漏和内存泄漏等问题。RAII 机制在 C++ 等编程语言中得到广泛应用,是一种有效的资源管理方式。

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

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

相关文章

MYSQL01高级_Linux版安装、各级别字符集、字符集与比较规则、SQL大小写规范

文章目录 ①. MySQL - linux版安装②. 字符集的相关操作③. 各级别的字符集④. 字符集与比较规则(了解)⑤. SQL大小写规范⑥. sql_mode的合理设置 ①. MySQL - linux版安装 ①. 进入mysql官网,找到安装文件 ②. 将抽取出来的文件放在linux下的opt下 MySQL Community Serv…

视频在线压缩

video2edit 一款免费的在线视频编辑软件&#xff0c;可以进行视频合并、视频剪辑、视频压缩以及转换视频格式等。 链接地址&#xff1a;在线视频编辑器和转换器 - 编辑&#xff0c;转换和压缩视频文件 打开视频压缩页面&#xff0c;上传想要压缩视频&#xff0c;支持MP4&…

ffmpeg单张图片生成固定时长的视频

ffmpeg -r 25 -f image2 -loop 1 -i fps_1.jpg -vcodec libx264 -pix_fmt yuv420p -s 1080*1920 -r 25 -t 30 -y fps.mp4这个命令将 fps_1.jpg 图片转换为一个 30 秒长的视频&#xff0c;分辨率为 1920x1080&#xff0c;帧率为 25 帧/秒&#xff0c;并使用 libx264 编码器进行压…

1.3 vue ui框架-element-ui框架

1 前言 ElementUI是一套基于VUE2.0的桌面端组件库&#xff0c;ElementUI提供了丰富的组件帮助开发人员快速构建功能强大、风格统一的页面。 ElementUI官网 https://element.eleme.io 2 安装 运行命令 cnpm i element-ui -S -S表示只在该项目下安装&#xff0c;不是全局安…

C++指针(二)

个人主页&#xff1a;PingdiGuo_guo 收录专栏&#xff1a;C干货专栏 文章目录 1.数组指针 1.1数组指针的概念 1.2数组指针的用处 1.3数组指针的操作 1.4二维数组如何访问 1.5数组指针访问流程 1.6数组指针的练习题 2.指针数组 2.1指针数组的概念 2.2指针数组的用处 2…

使用Python,networkx绘制有向层级结构图

使用Python&#xff0c;networkx绘制有向层级结构图 1. 效果图2. 源码2.1 tree.txt2.2 pyNetworkx.py参考 上一篇介绍了&#xff1a;1. 使用Python&#xff0c;networkx对卡勒德胡赛尼三部曲之《群山回唱》人物关系图谱绘制 当前博客介绍&#xff1a; 2. 使用Python&#xff0c…

【C++】map和set——树形结构的关联式容器

目录 一、序列式容器和关联式容器 二、键值对pair 三、树形结构的关联式容器 3.1 set 3.1.1.set的模板参数 3.1.2. set的构造 3.1.3. set的迭代器 3.1.4. set的容量 3.1.5. set的操作 3.1.6. set的修改 3.1.7 set的使用示范 3.2 map 3.2.1. map的模板参数说明 3.…

解决android studio build Output中文乱码

1.效果如下所示&#xff1a; 代码运行报错的时候&#xff0c;Build Output报的错误日志中中文部分出现乱码&#xff0c;导致看不到到底报的什么错。 2.解决办法如下&#xff1a; 点击Android studio开发工具栏的Help-Edit Custom VM Options....&#xff0c;Android studio会…

【Acwing】差分矩阵

图1&#xff1a;a和b数组映射表 由于a是b的前缀和数组&#xff0c;因此改变b[ x1][ y1]之后&#xff0c;受到影响的a中元素如右半图所示 图2&#xff1a;求b数组的前缀和 #include<bits/stdc.h> using namespace std;int n,m,q; int a[1010][1010]; int b[1010][1010]…

使用Fabric创建的canvas画布背景图片,自适应画布宽高

之前的文章写过vue2使用fabric实现简单画图demo&#xff0c;完成批阅功能&#xff1b;但是功能不完善&#xff0c;对于很大的图片就只能显示一部分出来&#xff0c;不符合我们的需求。这就需要改进&#xff0c;对我们设置的背景图进行自适应。 有问题的canvas画布背景 修改后的…

【字典树】【KMP】【C++算法】3045统计前后缀下标对 II

作者推荐 动态规划的时间复杂度优化 本文涉及知识点 字符串 字典树 KMP 前后缀 LeetCode:3045统计前后缀下标对 II 给你一个下标从 0 开始的字符串数组 words 。 定义一个 布尔 函数 isPrefixAndSuffix &#xff0c;它接受两个字符串参数 str1 和 str2 &#xff1a; 当 st…

k8s-项目测试环境部署

部署规划 概述 项目开发好后&#xff0c;我们需要部署&#xff0c;我们接下来就基于 阿里云云效 阿里云容器镜像服务 k8s 搭建部署环境 阿里云云效 : 放代码&#xff0c;可以做cicd&#xff08;https://www.aliyun.com/product/yunxiao&#xff09; 阿里云容器镜像服务 :…

在 Linux 环境下安装 Kibana

目录 一、Kibana 是什么 二、在 Linux 环境下安装 Kibana 1、下载安装包 2、解压 3、修改 Kibana的配置文件 config/kibana.yml 4、启动 5、浏览器登录 Kibana 6、测试查询 一、Kibana 是什么 Kibana 是通向 Elastic 产品集的窗口。 它可以在 Elasticsearch 中对数据进…

java爬取深圳新房备案价

Java爬取深圳新房备案价 这是我做好效果,一共分3个页面 1、列表;2、统计;3、房源表 列表 价格分析页面 房源页面 一、如何爬取 第一步:获取深圳新房备案价 链接是:http://zjj.sz.gov.cn/ris/bol/szfdc/index.aspx 第二步:通过楼盘名查询获取明细 链接:http://z…

YOLOv9理性解读 | 网络结构损失函数耗时评估

论文&#xff1a;https://arxiv.org/pdf/2402.13616.pdfHuggingFace Demo&#xff1a;https://hf-mirror.com/spaces/kadirnar/Yolov9Github&#xff1a;https://github.com/WongKinYiu/yolov9 由台北中研院和台北科技大学等机构的研究团队推出的新的目标检测算法&#xff0c;…

应用存储与持久化数据卷

1、PV 引入场景&#xff1a; ① Deployment 管理的 pod&#xff0c;在做镜像升级的过程中&#xff0c;会产生新的 pod并且删除旧的 pod &#xff0c;新旧 pod 之间如何复用数据&#xff1f; ② 宿主机宕机的时候&#xff0c;如何实现带卷迁移&#xff1f; ③ 多个 pod 之间&…

基于springboot+vue的相亲网站

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

Stable Video Diffusion(SVD)视频生成模型发布 1.1版

前言 近日&#xff0c;随着人工智能技术的飞速发展&#xff0c;图像到视频生成技术也迎来了新的突破。特别是Stable Video Diffusion&#xff08;SVD&#xff09;模型的最新版本1.1&#xff0c;它为我们带来了从静态图像生成动态视频的全新能力。本文将深入解析SVD 1.1版本的核…

gpt-3.5-turbo与星火认知大模型v3.5回答对比

创建kernel // Create a kernel with OpenAI chat completionKernel kernel Kernel.CreateBuilder().AddOpenAIChatCompletion(modelId:"使用的模型id" ,apiKey: "APIKey").Build();使用讯飞星火认知大模型的话&#xff0c;可以参考我这一篇文章&#xff…

Linux系统——Nginx负载均衡模式

目录 一、Nginx优点 二、Nginx配置项——Conf Upstream 模块 三、Nginx负载均衡 1.负载均衡策略 1.1轮询 1.2IP_hash 1.3URL_hash 1.4Least_conn 1.5Weight 1.6Fair 2.Nginx负载均衡配置状态参数 3.什么是会话保持 3.1会话保持有什么作用呢 3.2Nginx会话保持 3…