百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露

gudong366 2025-03-24 15:11 7 浏览

一:背景

1. 讲故事

前面跟大家分享过一篇 C# 调用 C代码引发非托管内存泄露 的文章,这是一个故意引发的正向泄露,这一篇我们从逆向的角度去洞察引发泄露的祸根代码,这东西如果在 windows 上还是很好处理的,很多人知道开启一个 ust 即可,让操作系统帮忙介入,在linux上就相对复杂一点了,毕竟Linux系统是一个万物生的场地,没有一个人统管全局,在调试领域这块还是蛮大的一个弊端。

二:案例分析

1. 一个小案例

这里我还是用之前的例子,对应的 C 代码 和 C#代码 如下:

  1. C 代码


#include
#include
#include
#include

#define BLOCK_SIZE (10 * 1024) // 每个块 10K
#define TOTAL_SIZE (1 * 1024 * 1024 * 1024) // 总计 1GB
#define BLOCKS (TOTAL_SIZE / BLOCK_SIZE) // 计算需要的块数

void heapmalloc()
{
uint8_t *blocks[BLOCKS]; // 存储每个块的指针

// 分配 1GB 内存,分成多个小块
for (size_t i = 0; i < BLOCKS; i++)
{
blocks[i] = (uint8_t *)malloc(BLOCK_SIZE);
if (blocks[i] == )
{
printf("内存分配失败!\n");
return;
}

// 确保每个块都被实际占用
memset(blocks[i], 20, BLOCK_SIZE);
}

printf("已经分配 1GB 内存在堆上!\n");
}

  1. C#代码

using System.Runtime.InteropServices;

namespaceCSharpApplication;

classProgram
{
[DllImport("libmyleak.so", CallingConvention = CallingConvention.Cdecl)]
public static extern void heapmalloc();

static void Main(string[] args)
{
heapmalloc();
Console.ReadLine();
}
}

2. heaptrack 跟踪

heaptrack 是一款跟踪 C/C++ heap分配的工具,它会拦截所有的 malloc、calloc、realloc 和 free 函数调用,并记录分配的调用栈信息,总的来说这工具和 C# 半毛钱关系都没有,主要是图它的如下三点:

  1. 能够记录到分配的调用栈信息,虽然只有非托管部分。
  2. 对程序的影响相对小。
  3. 有可视化的工具观察跟踪文件。

依次安装 heaptrackheaptrack-gui ,参考如下:


root@ubuntu2404:/data# sudo apt install heaptrack
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
heaptrack is already the newest version (1.5.0+dfsg1-2ubuntu3).
0 upgraded, 0 newly installed, 0 to remove and 217 not upgraded.

root@ubuntu2404:/data/CSharpApplication/bin/Debug/net8.0# sudo apt install heaptrack-gui
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
heaptrack-gui is already the newest version (1.5.0+dfsg1-2ubuntu3).
0 upgraded, 0 newly installed, 0 to remove and 217 not upgraded.

安装好以后可以用 heaptrack dotnet CSharpApplication.dll 对 dotnet 程序进行跟踪,当泄露到一定程序之后,可以用 dotnet-dump 生成一个转储文件,然后 Ctrl+C 进行中断,


root@ubuntu2404:/data/CSharpApplication/bin/Debug/net8.0# heaptrack dotnet CSharpApplication.dll
heaptrack output will be written to "/data/CSharpApplication/bin/Debug/net8.0/heaptrack.dotnet.4368.zst"
starting application, this might take some time...
NOTE: heaptrack detected DEBUGINFOD_URLS but will disable it to prevent
unintended network delays during recording
If you really want to use DEBUGINFOD, export HEAPTRACK_ENABLE_DEBUGINFOD=1
已经分配 1GB 内存在堆上!
[createdump] Gathering state for process 4383 dotnet
[createdump] Writing full dump to file /data/CSharpApplication/bin/Debug/net8.0/core_20250307_102814
[createdump] Written 1252216832 bytes (305717 pages) to core file
[createdump] Target process is alive
[createdump] Dump successfully written in 23681ms

root@ubuntu2404:/data/CSharpApplication/bin/Debug/net8.0# heaptrack stats:
allocations: 122151
leaked allocations: 108551
temporary allocations: 4118

root@ubuntu2404:/data/CSharpApplication/bin/Debug/net8.0# ls -lh
total 1.2G
-rwxr-xr-x 1 root root 74K Mar 5 22:38 CSharpApplication
-rw-r--r-- 1 root root 421 Mar 5 21:52 CSharpApplication.deps.json
-rw-r--r-- 1 root root 4.5K Mar 5 22:38 CSharpApplication.dll
-rw-r--r-- 1 root root 11K Mar 5 22:38 CSharpApplication.pdb
-rw-r--r-- 1 root root 257 Mar 5 21:52 CSharpApplication.runtimeconfig.json
-rw------- 1 root root 1.2G Mar 7 10:28 core_20250307_102814
-rw-r--r-- 1 root root 277K Mar 7 10:32 heaptrack.dotnet.4368.zst
-rwxr-xr-x 1 root root 16K Mar 5 21:52 libmyleak.so

从卦中看已产生了一个 heaptrack.dotnet.4368.zst 文件,这是一种专有的压缩格式,可以借助 heaptrack_print 转成 txt 文件,方便从生产上拿下来分析。


root@ubuntu2404:/data/CSharpApplication/bin/Debug/net8.0# heaptrack_print heaptrack.dotnet.4368.zst > heaptrack.txt

真实的场景下肉眼观察 heaptrack.txt 是不大现实的,所以还得借助可视化工具,观察 Bottom-Up 选择项,信息如下:

  • 左边面板

可以观察到 Leaked 最多的是 libmyleak.so 中的 heapmalloc 函数。

  • 右边面板

可以观察到执行 heapmalloc 方法的上层函数,给大家截图二张。

稍微仔细看的话,会发现Backtrace上有很多的 unresolved 符号,这个没办法,毕竟人家是 C/C++ 的跟踪器,和你C#没关系,那这些未解析的符号到底是什么函数呢?

3. 未解析符号的地址在哪里

既然是 C# 程序,大概率就是 C#方法了,那如何把方法名给找出来呢?熟悉.NET高级调试的朋友此时应该轻车熟路了,思路如下:

  1. 寻找 指令地址。

一般来说解析不出来都会生成对应的 指令地址 的,这个可以到 heaptrack.txt 中寻找蛛丝马迹,截图如下:

  1. 抓 core 文件

要想抓 .NET 的 core 文件,dotnet-dump 即可,这个就不介绍了哈,参考如下:


root@ubuntu2404:/data/CSharpApplication/bin/Debug/net8.0# ps -ef | grep CSharp
root 4368 2914 0 10:25 pts/0 00:00:00 /bin/sh /usr/bin/heaptrack dotnet CSharpApplication.dll
root 4383 4368 2 10:25 pts/0 00:00:03 dotnet CSharpApplication.dll
root 4421 4336 0 10:28 pts/3 00:00:00 grep --color=auto CSharp
root@ubuntu2404:/data/CSharpApplication/bin/Debug/net8.0# dotnet-dump collect -p 4383
Writing full to /data/CSharpApplication/bin/Debug/net8.0/core_20250307_102814
Complete
root@ubuntu2404:/data/CSharpApplication/bin/Debug/net8.0# ls -lh
total 1.2G
-rwxr-xr-x 1 root root 74K Mar 5 22:38 CSharpApplication
-rw-r--r-- 1 root root 421 Mar 5 21:52 CSharpApplication.deps.json
-rw-r--r-- 1 root root 4.5K Mar 5 22:38 CSharpApplication.dll
-rw-r--r-- 1 root root 11K Mar 5 22:38 CSharpApplication.pdb
-rw-r--r-- 1 root root 257 Mar 5 21:52 CSharpApplication.runtimeconfig.json
-rw------- 1 root root 1.2G Mar 7 10:28 core_20250307_102814
-rw-r--r-- 1 root root 0 Mar 7 10:25 heaptrack.dotnet.4368.zst
-rwxr-xr-x 1 root root 16K Mar 5 21:52 libmyleak.so

core_20250307_102814 生成好之后,就可以借助 sos 的 ip2md 寻找这个指令地址对应的C#方法名了。


root@ubuntu2404:/data/CSharpApplication/bin/Debug/net8.0# dotnet-dump analyze core_20250307_102814
Loading core dump: core_20250307_102814 ...
Ready to process analysis commands. Type 'help' to list available commands or 'help [command]' to get detailed help on a command.
Type 'quit' or 'exit' to exit the session.
> ip2md 0x7ea6627119f6
MethodDesc: 00007ea6627cd3d8
Method Name: ILStubClass.IL_STUB_PInvoke()
Class: 00007ea6627cd300
MethodTable: 00007ea6627cd368
mdToken: 0000000006000000
Module: 00007ea66279cec8
IsJitted: yes
Current CodeAddr: 00007ea662711970
Version History:
ILCodeVersion: 0000000000000000
ReJIT ID: 0
IL Addr: 0000000000000000
CodeAddr: 00007ea662711970 (MinOptJitted)
NativeCodeVersion: 0000000000000000
> ip2md 0x7ea662711947
MethodDesc: 00007ea66279f328
Method Name: CSharpApplication.Program.Main(System.String[])
Class: 00007ea6627bb640
MethodTable: 00007ea66279f358
mdToken: 0000000006000002
Module: 00007ea66279cec8
IsJitted: yes
Current CodeAddr: 00007ea662711920
Version History:
ILCodeVersion: 0000000000000000
ReJIT ID: 0
IL Addr: 00007ea6de8f1250
CodeAddr: 00007ea662711920 (MinOptJitted)
NativeCodeVersion: 0000000000000000
Source file: /data/CSharpApplication/Program.cs @ 12

到这里恍然大悟,然来调用路径为:CSharpApplication.Program.Main -> PInvoke -> heapmalloc ,至此真相大白。

三:总结

Linux 上的调试总觉得少了一位总管太监,能分析 非托管内存的工具 不鸟dotnet, 同样的,能分析 dotnet托管内存的工具 也不鸟非托管内存,大家各自为政。。。 让习惯使用通杀一切的windbg使用者太不可思议了。

相关推荐

U盘文件被删怎么简单恢复(u盘里的文件被误删了怎么找回)

现在这个社会不是靠关系靠路子,主要还是靠实力。刘强在机关工作,人长得帅气,工作能力又强。唯独一样不好,脾气太大,动不动就发火,因为小事常和同事发生口角。一次他火大的差点把办公桌给掀翻了,领导见他野蛮的...

不小心删除了一些文件?9 个最佳免费硬盘恢复软件

恢复您曾经无意或意外删除的所有文件和数据。您是否曾经错误地删除了一个对您的工作至关重要并导致您丢失所有进度的文件?我们为您提供了一些最好的免费硬盘恢复软件,以帮助您恢复意外删除的文件,以解决您的文件删...

Studio 中文版:数据救援神器,误删 / 分区损坏 / RAID 恢复一键找回

Studio中文版:数据救援神器,误删/分区损坏/RAID恢复一键找回当文件意外删除、分区损坏,或RAID阵列崩溃时,一款可靠的数据恢复工具往往能挽回关键损失。R-Studio中文版...

你值得拥有的11款Linux数据恢复工具

如果你使用的是Linux操作系统,那么你一定想知道一旦硬盘崩溃的话又该如何保存和恢复数据。其实,现在有很多Linux数据恢复工具可以让我们摆脱数据安全的困扰。小编已经为各位准备好了一些最好的Linux...

误删文件内容怎么恢复(误删文件内容怎么恢复回来)

  在日常使用电脑的过程中,误删文件的情况时有发生。无论是由于操作失误还是病毒攻击,误删文件都会给我们带来不小的困扰。幸运的是,随着技术的发展,误删文件恢复已不再是难题。本文将介绍几款国内外知名的误删...

u盘如何恢复删除的文件?推荐5款u盘数据恢复软件!

在日常生活与工作中,U盘作为便捷的数据存储载体,频繁用于传输和保存各类重要文件。然而,误删文件的情况却时有发生,无论是珍贵的照片、重要的工作文档,还是精心制作的视频,一旦删除,都可能带来不小的麻烦。...

怎么恢复删除的数据?5种有效的数据恢复方法汇总!

在数字化办公与生活的时代,电脑里的每一份数据都承载着重要信息。然而,一个误操作就可能导致数据被删除,无论是尚未保存的重要文档,还是珍藏多年的照片,都可能瞬间“消失”。但其实,数据删除并不意味着永久丢...

u盘删除文件怎么找回?5个数据恢复工具汇总,助你巧妙恢复数据!

在日常使用U盘的过程中,误删文件的情况时有发生,重要的工作文档、珍贵的照片视频一旦消失,难免让人焦急万分。别担心,只要选对数据恢复工具,被删除的数据仍有找回的可能。下面就为你汇总5款实用的数据...

Linux下恢复误删文件:思路+实践(linux删除如何恢复)

周五篮球群里有人问误删文件了怎么恢复,得知是ext4文件系统之后我推荐了ext4magic这个工具,然后又有人提到了xfs的话怎么办,正好前几天看到DaveChinner在邮件列表里提到了这个问题,...

苹果放大招!不用虚拟机了,Mac直接跑Linux容器,开发者效率翻倍

苹果这次真给开发者送福利了!今天凌晨(6月10日),苹果在官宣的Containerization框架直接炸了技术圈——Mac现在能原生运行Linux容器镜像了!这可不是虚拟机那种“套娃”方案,而是基...

7 款老牌经典软件,值得收藏(经典老歌软件)

Calibrehttps://calibre-ebook.com/Calibre是一个电脑电子书管理软件。肯定有人说了,电子书还要管理?那当然了。它的功能更强大的让你想象不到,首先它可以导入PDF,...

神仙级的免费开源电子书阅读器,还支持听书功能

神仙级的免费开源电子书阅读器,还支持听书功能,极空间部署『KoodoReader』哈喽小伙伴们好,我是Stark-C~前段时间不是给大家分享的电子书管理工具『TaleBook』嘛~,然后就有粉丝私信...

如何在Ubuntu系统中重置root密码(ubuntu忘记密码重置root密码命令)

很多人有个问题,就是喜欢把密码设置得很长很复杂,结果谁也没防住,却成功防住了自己ヽ(.ˇдˇ;)ノ对于现代人,特别是年轻人,都有过忘记密码的经历吧。在这篇文章中,我们来了解如何在Ubuntu1...

5款功能强大的PDF阅读器,让PDF阅读更轻松

分享5款功能强大的PDF阅读器,拥有丰富的PDF阅读工具,支持PDF文档划线、笔记、标记等操作,让PDF阅读更轻松!1.嗨动PDF编辑器一款实用的PDF处理软件,不仅可以阅读PDF文档,还能直接编辑、...

上班摸鱼利器! 免费好用的电子书阅读器,NAS轻松部署Koodo Reader

哈喽,大家好我是生活爱好者。笔者也是一名小说爱好者,平时用手机用某信读书,会员也开了,在家看体验也不错,但是上班的时候,在工作快速完成之后,想摸个鱼用手机就不太方便啦,作为爱折腾的人,必须要工作认真,...