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        allocationsntdll!RtlpAllocateHeapInternal+948D5taos!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+10ntdll!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++ 等编程语言中得到广泛应用,是一种有效的资源管理方式。

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

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

相关文章

新品齐发!小牛电动打造全场景高端化产品阵列!

2 月 29 日&#xff0c;全球智能城市出行品牌小牛电动发布“新世代性能旗舰”电摩NX、电自NXT&#xff0c;以及“全场景智驾越野电摩”X3三款新品。同时&#xff0c;与知名体育电竞俱乐部——JDG京东电子竞技俱乐部携手&#xff0c;打造“英雄的联盟”超级形象&#xff0c;引领…

学习大语言模型(LLM),从这里开始

在见识了ChatGPT的各种强大能力后&#xff0c;不少 NLP一线从业人员很自然地想到&#xff0c;以后开发者只要借助 ChatGPT&#xff0c;就可以做到现在大部分NLP工程师在做的事&#xff0c;比如文本分类、实体抽取、文本推理等。甚至随着大语言模型&#xff08;largelanguagemod…

【JVM篇】什么是运行时数据区

文章目录 &#x1f354;什么是运行时数据区⭐程序计数器⭐栈&#x1f50e;Java虚拟机栈&#x1f388;栈帧的内容 &#x1f50e;本地方法栈 ⭐堆⭐方法区 &#x1f354;什么是运行时数据区 运行时数据区指的是jvm所管理的内存区域&#xff0c;其中分为两大类 线程共享&#xf…

2024亚马逊全球开店注册前需要准备什么?

在2023年出海四小龙SHEIN、Temu、速卖通AliExpress、TikTok Shop快速增长扩张&#xff0c;成为了中国跨境卖家“逃离亚马逊”的新选择。但是&#xff0c;跨境电商看亚马逊。当前&#xff0c;亚马逊仍然是跨境电商行业的绝对老大&#xff0c;占有将近70%成以上的业务份额。 作为…

【电商干货】5分钟了解电商数据API测试完整流程,建议收藏!可获取免费测试key!

电商API是什么&#xff1f; API是application programming interface&#xff08;应用程序接口&#xff09;的简称&#xff0c;是一些预先定义的函数。目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力&#xff0c;而又无需访问源码&#xff0c;或理解内部…

快速下载Huggingface的大语言模型

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、Huggingface是什么&#xff1f;二、基于官方huggingface-cli下载&#xff08;基础&#xff0c;断线风险&#xff09;1.安装hf下载环境2.配置环境变量3.注册…

WPF 【十月的寒流】学习笔记(2):MVVM中是怎么实现通知的

文章目录 前言相关链接代码仓库项目配置代码初始代码ViewPersonViewModel 尝试老办法通知解决方案ObservableCollectionBindingListICollectionView 总结 前言 我们这次详细了解一下列表通知的底层是怎么实现的 相关链接 十月的寒流 MVVM实战技巧之&#xff1a;可被观测的集合…

Appium + mitmProxy 实现APP接口稳定性测试

随着 App 用户量的不断增长&#xff0c;任何小的问题都可能放大成严重的线上事故&#xff0c;为了避免对App造成损害的任何可能性&#xff0c;我们必须从各个方面去思考 App 的稳定性建设&#xff0c;尽可能减少任何潜在的威胁。 1.背景介绍 为了保障 App 的稳定性&#xff0…

仿牛客网项目---社区首页的开发实现

从今天开始我们来写一个新项目&#xff0c;这个项目是一个完整的校园论坛的项目。主要功能模块&#xff1a;用户登录注册&#xff0c;帖子发布和热帖排行&#xff0c;点赞关注&#xff0c;发送私信&#xff0c;消息通知&#xff0c;社区搜索等。这篇文章我们先试着写一下用户的…

ELK 简介安装

1、概念介绍 日志介绍 日志就是程序产生的&#xff0c;遵循一定格式&#xff08;通常包含时间戳&#xff09;的文本数据。 通常日志由服务器生成&#xff0c;输出到不同的文件中&#xff0c;一般会有系统日志、 应用日志、安全日志。这些日志分散地存储在不同的机器上。 日志…

【Leetcode每日一刷】动态规划算法: 62. 不同路径、63. 不同路径 II

博主简介&#xff1a;努力学习和进步中的的22级计科生博主主页&#xff1a; Yaoyao2024每日一句: “ 路虽远&#xff0c;行则将至。事虽难&#xff0c;做则可成。” 前言 前言&#xff1a;动规五部曲 以下是《代码随想录》作者总结的动规五部曲 确定dp数组&#xff08;dp tab…

Flink——芒果TV的实时数仓建设实践

目录 一、芒果TV实时数仓建设历程 1.1 阶段一&#xff1a;Storm/Flink JavaSpark SQL 1.2 阶段二&#xff1a;Flink SQLSpark SQL 1.3 阶段三&#xff1a;Flink SQLStarRocks 二、自研Flink实时计算调度平台介绍 2.1 现有痛点 2.2 平台架构设计 三、Flink SQL实时数仓分…

AI智能分析网关V4:抽烟/打电话/玩手机行为AI算法及场景应用

抽烟、打电话、玩手机是人们在日常生活中常见的行为&#xff0c;但这些行为在某些场合下可能会带来安全风险。因此&#xff0c;对于这些行为的检测技术及应用就变得尤为重要。今天来给大家介绍一下TSINGSEE青犀AI智能分析网关V4抽烟/打电话/玩手机检测算法及其应用场景。 将监控…

输入一个字符串,将其中的数字字符移动到非数字字符之后

输入一个字符串&#xff0c;将其中的数字字符移动到非数字字符之后&#xff0c;并保持数字字符贺非数字字符输入时的顺序。 代码&#xff1a; #include <cstdio> #include <queue> using namespace std; int main() {char str[200];fgets(str, 200, stdin);//读入…

每周一算法:双端队列广搜

题目链接 电路维修 题目描述 达达是来自异世界的魔女&#xff0c;她在漫无目的地四处漂流的时候&#xff0c;遇到了善良的少女翰翰&#xff0c;从而被收留在地球上。翰翰的家里有一辆飞行车。有一天飞行车的电路板突然出现了故障&#xff0c;导致无法启动。 电路板的整体结…

【学习心得】Python调用JS的三种常用方法

在做JS逆向的时候&#xff0c;一种情况是直接用Python代码复现JS代码的功能&#xff0c;达成目的。但很多时候这种方法有明显的缺点&#xff0c;那就是一旦JS代码逻辑发生了更改&#xff0c;你就得重写Python的代码逻辑非常不便。于是第二种情况就出现了&#xff0c;我直接得到…

vue项目从后端下载文件显示进度条或者loading

//API接口 export const exportDownload (params?: Object, peCallback?: Function) > {return new Promise((resolve, reject) > {axios({method: get,url: ,headers: {access_token: ${getToken()},},responseType: blob,params,onDownloadProgress: (pe) > {peC…

10分钟SkyWalking与SpringBoot融合并整合到Linux中

1.依赖配置 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2.2.0.RELEASE</version></dependency><dependency><groupId>org.springframe…

IP源防攻击IPSG(IP Source Guard)

IP源防攻击IPSG&#xff08;IP Source Guard&#xff09;是一种基于二层接口的源IP地址过滤技术&#xff0c;它能够防止恶意主机伪造合法主机的IP地址来仿冒合法主机&#xff0c;还能确保非授权主机不能通过自己指定IP地址的方式来访问网络或攻击网络。 2.1 IPSG基本原理 绑定…

深入探讨Java中的OutputStreamWriter类

咦咦咦&#xff0c;各位小可爱&#xff0c;我是你们的好伙伴——bug菌&#xff0c;今天又来给大家普及Java SE相关知识点了&#xff0c;别躲起来啊&#xff0c;听我讲干货还不快点赞&#xff0c;赞多了我就有动力讲得更嗨啦&#xff01;所以呀&#xff0c;养成先点赞后阅读的好…