惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

J
Java Code Geeks
Martin Fowler
Martin Fowler
B
Blog RSS Feed
D
DataBreaches.Net
L
LangChain Blog
月光博客
月光博客
S
SegmentFault 最新的问题
阮一峰的网络日志
阮一峰的网络日志
V
Visual Studio Blog
美团技术团队
Jina AI
Jina AI
博客园 - 司徒正美
雷峰网
雷峰网
Last Week in AI
Last Week in AI
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
IT之家
IT之家
博客园 - 三生石上(FineUI控件)
WordPress大学
WordPress大学
小众软件
小众软件
罗磊的独立博客
博客园_首页
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
A
About on SuperTechFans
Engineering at Meta
Engineering at Meta

博客园 - 一线码农

记一次 .NET 某智慧医保云服务Linux 非托管泄露分析 .NET 高级调试技术:超越基础 Dump 分析 .NET 生产环境调试实战指南 记一次 .NET 某光电成像后端解析系统 内存暴涨分析 记一次 .NET 某电力后台监控系统 内存暴涨分析 记一次 .NET 某注塑模具系统 CPU爆高分析 记一次 .NET 某集群管理软件 内存暴涨分析 记一次 .NET 某智慧工厂视觉程序 崩溃分析 记一次 .NET 某低代码开发框架 内存暴涨分析 记一次 .NET 某MES上位机拍照系统 内存暴涨分析 记一次 .NET 某RFID标签打印客户端 崩溃分析 对 .NET FileSystemWatcher引发内存碎片化的 反思 DotMemory系列:4. 如何分析进程的转储文件 DotMemory系列:3. 堆碎片化引发的内存暴涨分析 DotMemory系列:2. 事件泄露引发的内存暴涨分析 DotMemory系列:1. 终结队列积压引发的内存暴涨分析 记一次 .NET 某理财管理客户端 OOM溢出分析 记一次 .NET 某医联体管理系统 崩溃分析 记一次 .NET 某光放测试系统 崩溃分析 记一次 .NET 某药品缺陷高速检测系统 卡慢分析 聊一聊 .NET超高内存故障分析方法 的反思 记一次 .NET 某企业ECM内容管理系统 内存暴涨分析 记一次 .NET 某跨境物流系统 内存暴涨分析 记一次 .NET 某中医药附属医院门诊系统 崩溃分析 聊一聊 .NET 中的 CompositeChangeToken 聊一聊 .NET 中的 CancellationTokenSource 记一次 .NET 某CRM物流行业管理系统 崩溃分析
DotMemory系列:5. 如何实现自动化抓取和应用自托管
一线码农 · 2025-11-18 · via 博客园 - 一线码农

一:背景

1. 讲故事

前面几篇我们都是手工安装 dotmemory 软件,然后在程序的合适时机抓取snapshot,这种方式在绝大多数场景下都没有问题,但在一些精细化的场景下,如果能够实现自动化抓取,那就比较🐂👃了,这篇我们就来聊一聊这玩意。

二:如何实现自动化抓取

1. 测试代码

所谓的自动化抓取,意思就是用代码来控制 snapshot 的抓取时机,而不是你在 UI 上点来点去,为了方便测试,先上一段测试代码,参考如下:


    internal class Program
    {
        static void Main()
        {
            var analyzer = new MemoryAnalyzer();
            analyzer.ProcessData();

            Console.ReadLine();
        }
    }

    public class MemoryAnalyzer
    {
        private readonly List<string> _data = new();

        public void ProcessData()
        {
            // 模拟内存密集型操作
            for (int i = 0; i < 10000; i++)
            {
                _data.Add(new string('x', 1000));
            }

            Console.WriteLine("数据处理完成,3秒后生成快照...");
            Thread.Sleep(3000);

            MemoryProfiler.GetSnapshot("ProcessDataSnapshot");
            Console.WriteLine("快照已生成");
        }
    }

上面的代码非常简单,我想在 ProcessData() 方法内的某一个时点通过 MemoryProfiler.GetSnapshot 方法自动化抓取snapshot,这个让你在UI上点击,你根本无法做到。

2. dotmemory 集成交互

代码里埋好点之后,接下来打开 dotmemory,使用 Using API 模式,这样就相当于给程序开了一个口子,截图如下:

接下来点击 Start 按钮,可以看到程序自动的帮我们生成了一个叫 ProcessDataSnapshot 的snapshot,是不是挺有意思的,截图如下:

三:如何实现自托管

1. 测试代码

所谓的自托管就是让代码自己去下载 Console of DotMemory,全程不需要人为干预,最终会产生一个后缀为 *.dmw 的跟踪文件,参考代码如下:


    internal class Program
    {
        static void Main(string[] args)
        {
            DotMemory.Init();
            var config = new DotMemory.Config();
            config.SaveToDir(@"E:\testdump");

            DotMemory.Attach(config);

            Console.WriteLine("=== 内存分析开始 ===\n");

            var memoryDemo = new MemoryDemo();

            DotMemory.GetSnapshot("Initial");
            Console.WriteLine("初始快照已生成");

            memoryDemo.CreateObjects();
            DotMemory.GetSnapshot("AfterCreation");
            Console.WriteLine("对象创建后快照已生成");

            memoryDemo.Cleanup();
            DotMemory.GetSnapshot("AfterCleanup");
            Console.WriteLine("清理后快照已生成");

            Console.WriteLine("\n=== 分析完成 ===");

            DotMemory.Detach();
        }
    }

    public class MemoryDemo
    {
        private List<string> _strings = new();
        private List<byte[]> _buffers = new();
        private List<char[]> _charArrays = new();

        public void CreateObjects()
        {
            Console.WriteLine("创建对象中...");

            for (int i = 0; i < 500000; i++)
            {
                _strings.Add($"Data_{i}_{Guid.NewGuid()}_AdditionalPaddingDataToMakeStringLarger");
            }

            for (int i = 0; i < 5000; i++)
            {
                _buffers.Add(new byte[1024 * 200]);
            }

            for (int i = 0; i < 100; i++)
            {
                _buffers.Add(new byte[1024 * 1024 * 5]);
            }

            for (int i = 0; i < 10000; i++)
            {
                _charArrays.Add(new char[1024 * 50]);
            }

            Console.WriteLine($"已创建: {_strings.Count} 个字符串, {_buffers.Count} 个缓冲区, {_charArrays.Count} 个字符数组");
        }

        public void Cleanup()
        {
            Console.WriteLine("清理对象中...");

            _strings.Clear();
            _buffers.Clear();
            _charArrays.Clear();

            GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
            GC.Collect(2, GCCollectionMode.Forced, true, true);
            GC.WaitForPendingFinalizers();

            Console.WriteLine("清理完成");
        }
    }

上面的代码会在程序运行的三个阶段抓取snapshot,将程序运行起来之后,从下图可以清晰的看到已生成三个 snapshot 快照,是不是挺有意思,截图如下:

2. Console 版 DotMemory 分析

自托管借助的是 Console 版 DotMemory,不要小看这个 Console,它可以跨平台,也可以集成到各种 自动化发布工具 里面去,这里我就简单演示下在 ubuntu 上如何用 console 版抓 .net 程序的 snapshot 到 windows 上分析。

首先到 https://www.jetbrains.com/dotmemory/download/?section=commandline 上下载安装包,截图如下:


root@ubuntu2404:/data# tar -xzvf JetBrains.dotMemory.Console.linux-x64.2025.3.0.1.tar.gz

root@ubuntu2404:/data# ps -ef | grep dotnet
root        3007    2962  0 12:13 pts/1    00:00:00 dotnet Example_6_6.dll
root        3018    1938  0 12:13 pts/0    00:00:00 grep --color=auto dotnet
root@ubuntu2404:/data# ./dotMemory.sh get-snapshot 3007 --save-to-dir=./         
dotMemory.sh is deprecated and will soon be removed: Use the dotmemory command instead.
Performs memory profiling of .NET applications

Found 1 process(es):
  [3007] dotnet

Attaching to [3007] dotnet runtime...
Profiler connected. PID:3007, Core CLR runtime v8.0.15.0
  ATTACHED. Getting snapshot...
  [PID:3007] Saving snapshot... ~5.6 K objects
  [PID:3007] SNAPSHOT #1 SAVED.
  [PID:3007] Processing snapshot #1...
  [PID:3007] SNAPSHOT #1 READY.
Profiler disconnected. PID:3007

Saving workspace...
WORKSPACE SAVED
file:///data/[3007]-dotnet.2025-11-17T12-14-10.141.dmw

从上面的输出可以看到 dmw 文件已生成,接下来将文件导入到 windows 平台上,双击打开。

哈哈,是不是很完美。。。

四:总结

这个系列就先讲到这里吧,常见的功能应该都讲到了,总的来说 dotmemory 这款工具还有很多的缺点和不如意,但在专业的windbg介入之前,它起来了一个很好的拦截筛选作用。

图片名称