记一次 .NET某账本软件 非托管泄露分析
一:背景
1. 讲故事
中秋国庆长假结束,哈哈,在老家拍了很多的短视频,有兴趣的可以上B站观看:https://space.bilibili.com/409524162 ,今天继续给大家分享各种奇奇怪怪的.NET生产事故,希望能帮助大家在未来的编程之路上少踩坑。
话不多说,这篇看一个.NET程序集泄露导致的CLR私有堆泄露的案例,这个泄露和 JsonConvert 有关,哈哈,相信你肯定比较惊讶!
二:WinDbg 分析
1. 到底是哪里的泄露
首先观察一下进程的提交内存的大小,即通过 !address -summary 观察。
0:000> !address -summary
--- Usage Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
Free 390 7dfa`63fa8000 ( 125.978 TB) 98.42%
<unknown> 13628 205`32974000 ( 2.020 TB) 99.92% 1.58%
Heap 8143 0`4042b000 ( 1.004 GB) 0.05% 0.00%
Stack 186 0`1f8e0000 ( 504.875 MB) 0.02% 0.00%
Image 1958 0`09775000 ( 151.457 MB) 0.01% 0.00%
Other 9 0`001d7000 ( 1.840 MB) 0.00% 0.00%
TEB 62 0`0007c000 ( 496.000 kB) 0.00% 0.00%
PEB 1 0`00001000 ( 4.000 kB) 0.00% 0.00%--- Type Summary (for busy) ------ RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_MAPPED 312 200`00a06000 ( 2.000 TB) 98.92% 1.56%
MEM_PRIVATE 21717 5`91ecd000 ( 22.280 GB) 1.08% 0.02%
MEM_IMAGE 1958 0`09775000 ( 151.457 MB) 0.01% 0.00%--- State Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_FREE 390 7dfa`63fa8000 ( 125.978 TB) 98.42%
MEM_RESERVE 4509 205`0fc14000 ( 2.020 TB) 99.89% 1.58%
MEM_COMMIT 19478 0`8c434000 ( 2.192 GB) 0.11% 0.00%
当前的提交内存占用了 2.19G,进程堆占用 1G ,差不多占了一半,但不能说明就是非托管内存泄露,接下来继续观察下托管堆。
0:000> !eeheap -gc
Number of GC Heaps: 8
------------------------------
Heap 7 (000001C4971013A0)
generation 0 starts at 0x000001C817D201A0
generation 1 starts at 0x000001C817C878D8
generation 2 starts at 0x000001C817261000
ephemeral segment allocation context: nonesegment begin allocated size
000001C817260000 000001C817261000 000001C819013F98 0x1db2f98(31141784)
Large object heap starts at 0x000001C907261000segment begin allocated size
000001C907260000 000001C907261000 000001C907261018 0x18(24)
Pinned object heap starts at 0x000001C987261000
000001C987260000 000001C987261000 000001C9872ABA50 0x4aa50(305744)
Heap Size: Size: 0x1dfda00 (31447552) bytes.
------------------------------
GC Heap Size: Size: 0xba26488 (195191944) bytes.
从卦中可以看到当前的托管堆占用仅 195M,这就更好的验证当前确实存在非托管内存泄露,由于非托管内存没有开启 ust,也没有 perfview 的etw文件,所以没有好的方式进一步挖掘,到这里可能就止步不前了。
2. 到底是哪里的泄露
在 C# 所处的 Windows 进程中,其实有很多的堆,比如:crt堆,ntheap堆,gc堆,clr私有堆,堆外(VirtualAlloc),调试没有标准答案,不断的假设,试探,摸着石头过河,言外之意就是这个堆没问题,不代表其他堆也没有问题,这样想思路就比较顺畅了,我们可以看看其他的堆,比如这里的 CLR私有堆,使用 !eeheap -loader 观察。
0:000> !eeheap -loader
Loader Heap:
--------------------------------------
...
Module 00007ff846e034c0: Size: 0x0 (0) bytes.
Module 00007ff846e03930: Size: 0x0 (0) bytes.
Module 00007ff846e04180: Size: 0x0 (0) bytes.
Module 00007ff846e047e0: Size: 0x0 (0) bytes.
Module 00007ff846e04e40: Size: 0x0 (0) bytes.
Total size: Size: 0x0 (0) bytes.
--------------------------------------
Total LoaderHeap size: Size: 0x47252000 (1193615360) bytes total, 0x1f68000 (32931840) bytes wasted.
=======================================
从卦中可以看到有非常多的 module 迸射出来,估计有几万个,并且可以看到总的大小是 1.19G,到这里基本就搞清楚了,然来是 程序集泄露。
这里稍微补充一下,像这种问题早期可以使用 dotnet-counter 或者 Windows 的程序集指标 监控一下,或许你就能轻松找出原因,截图如下:
PS C:\Users\Administrator\Desktop> dotnet-counters monitor -n WebApplication2

而且 dotnet-counter 还是跨平台的,非常实用,大家可以琢磨琢磨,接下来抽一个module 用命令 !dumpmodule -mt 00007ff846e034c0 观察下,内部到底有哪些类型。
0:000> !dumpmodule -mt 00007ff846e034c0
Name: Unknown Module
Attributes: Reflection IsDynamic IsInMemory
Assembly: 000001c9e193b9e0
BaseAddress: 0000000000000000
...Types defined in this moduleMT TypeDef Name
------------------------------------------------------------------------------
00007ff846e03db0 0x02000002 Types referenced in this moduleMT TypeRef Name
------------------------------------------------------------------------------
00007ff820ff5748 0x02000002 xxx.xxx.Json.Converters.PolymorphismConverter`1
00007ff820e710f8 0x02000003 xxx.xxx.Models.IApiResult0:000> !dumpmt -md 00007ff846e03db0
Number of IFaces in IFaceMap: 0
--------------------------------------
MethodDesc TableEntry MethodDesc JIT Name
00007FF822F05FA8 00007ff823285b50 NONE xxx.Json.Converters.PolymorphismConverter`1
00007FF822EFD5E8 00007ff82323b1b8 NONE System.Text.Json.Serialization.JsonConverter`1
00007FF822EFD5F0 00007ff82323b1c8 NONE System.Text.Json.Serialization.JsonConverter`1
00007FF8414CB978 00007ff846e03d88 JIT IApiResultDynamicJsonConverter..ctor()
仔细分析卦中信息,可以很明显的看到。
- Json.Converters.PolymorphismConverter
看样子和牛顿有关系,并且还是一个自定义的 JsonConvert。
- IApiResult 和 IApiResultDynamicJsonConverter
看样子是一个接口的返回协议类,需要在代码中重点关注。
有了这些信息,接下来就是重点关注代码中的 PolymorphismConverter 类,果然就找到了一处。

从类的定义来看,一般这种东西都是在 ConfigureServices 方法中做 初始化定义 的,按理说问题不大,那为什么会有问题呢?还得要查下它的引用,终于给找到了,截图如下:

这是一个低级错误哈,每次读取 ApiResult.Data 的时候都要 jsonSerializerOptions.AddPolymorphism(); 操作,也就每次都会创建程序集,终于真相大白。
三:总结
这种程序集泄露导致的生产事故不应该哈,反应了团队中多人协作的时候还是有待提高!
相关文章:
记一次 .NET某账本软件 非托管泄露分析
一:背景 1. 讲故事 中秋国庆长假结束,哈哈,在老家拍了很多的短视频,有兴趣的可以上B站观看:https://space.bilibili.com/409524162 ,今天继续给大家分享各种奇奇怪怪的.NET生产事故,希望能帮助…...
Oracle笔记-对ROWNUM的一次理解(简单分页)
此博文记录时间:2023-05-05,发到互联网上是2023-10-09 这个在分页里面用得比较多,在MySQL中,通常使用limit去操作,而去感觉比较简单,Oracle中无此关键字。 通过查阅资料后,要实现分页需要用到…...
系统架构设计:10 论数据湖技术及其应用
目录 一 数据湖技术 1 数据库 2 数据仓库 3 数据库与数据仓库的对比 4 数据湖...
【MySQL】基本查询(三)聚合函数+group by
文章目录 一. 聚合函数二. group by子句结束语 建立如下表 //创建表结构 mysql> create table exam_result(-> id int unsigned primary key auto_increment,-> name varchar(20) not null comment 同学姓名,-> chinese float default 0.0 comment 语文成绩,->…...
基于KubeAdm搭建多节点K8S集群
基于KubeAdm搭建多节点K8S集群 1、基本流程(注意 docker 版本和kubeadm、kubelet、kubectl的关系)2、安装utils依赖(安装范围:主节点工作节点)3、安装docker (安装范围:主节点工作节点ÿ…...
VuePress实现自动获取文章侧边栏目录功能
👨🏻💻 热爱摄影的程序员 👨🏻🎨 喜欢编码的设计师 🧕🏻 擅长设计的剪辑师 🧑🏻🏫 一位高冷无情的编码爱好者 大家好,我是 DevO…...
nginx配置实例-负载均衡
1 实现效果: 浏览器访问nginx,输入访问nginx地址,然后负载均衡到tomcat8080和8002端口中 2 准备工作: 1)准备两台tomcat容器,一台8080,一台8081 2)在两台tomcat里面的webapps目录…...
Nginx的跨域问题解决
同源策略 浏览器的同源策略:是一种约定,是浏览器最核心也是最基本的安全功能,如果浏览器少了同源策略,则浏览器的正常功能可能都会受到影响。 同源: 协议、域名(IP)、端口相同即为同源 跨域问题 有两台服务器分别为A,B,如果从…...
ts的交叉类型是什么
交叉类型是TypeScript中的一种类型操作符,用于将多个类型合并成一个类型,表示同时拥有这些类型的属性和方法。交叉类型使用&符号进行连接。例如,以下代码定义了一个交叉类型Person & Serializable: interface Person {na…...
【【萌新的SOC学习之AXI接口简介】】
萌新的SOC学习之AXI接口简介 AXI总线的初步介绍 AXI 总线是 ARM AMBA 一部分 (高级可扩展接口) AMBA(高级微控制器总线架构) :开放的片内互联的总线标准,能再多主机设计中实现多个控制器和外围设备之间的连接和管理。…...
ios safari 浏览器跳转页面没有自适应
今天开发遇到了一个问题,当用户点击浏览器中的表单进行注册时,表单元素会放大,随后跳转页面无法还原到初始状态。 这是因为如果 的 font-size 被设定为 16px 或更大,那么 iOS 上的 Safari 将正常聚焦到输入表单中。但是ÿ…...
node、npm、nvm相关概念区别
node:一个基于Chrome V8引擎的JavaScript运行环境,让JavaScript 运行在服务端的开发平台。 nvm:node.js 版本管理工具。不同项目可能需要不同版本的 node,可以使用 nvm 来管理 node.js 版本。 安装教程参考 nvm下载及详细安装教程…...
Dubbo3应用开发—Dubbo3注册中心(zookeeper、nacos、consul)的使用
Dubbo3注册中心的使用 zookeeper注册中心的使用 依赖引入 <dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-dependencies-zookeeper-curator5</artifactId><version>${dubbo.version}</version><type>p…...
Chrome自动播放限制策略
原文链接:Chrome 自动播放限制策略 Web浏览器正在朝着更严格的自动播放策略发展,以便改善用户体验,最大限度地降低安装广告拦截器的积极性并减少昂贵和/或受限网络上的数据消耗。这些更改旨在为用户提供更大的播放控制权,并使开发…...
k8s安全机制
安全机制 一、机制说明二、认证(Authentication)HTTP Token 认证HTTP Base 认证HTTPS 证书认证(最严格) 三、鉴权(Authorization)角色角色绑定主体(subject)Role and ClusterRoleRol…...
Java多线程:Runnable与Callable的区别和原理
Java多线程:Runnable与Callable的区别和原理 在Java多线程编程中,我们经常使用Runnable和Callable接口来创建并执行线程。这两个接口都是Java.lang包中的部分,并且都用于实现多线程。虽然它们有些相似之处,但它们之间也存在明显的…...
解决yolo无法指定显卡的问题,实测v5、v7、v8有效
方法1 基本上这个就能解决了!!! 在train.py的最上方加上下面这两行,注意是最上面,其次指定的就是你要使用的显卡 import os os.environ[CUDA_VISIBLE_DEVICES]6方法2: **问题:**命令行参数指…...
arc 166 a
#include<bits/stdc.h> using namespace std; using VI vector<int>; using ll long long; const int mod 998244353; //当只有ab的时候,看作把a可以向右移动 //1 - x 是a 1 - y a //x中的 a 的 下标 < y 中 a 的下标 //这样就可以通过位移得到 …...
Lua05——Lua基本数据类型
lua 是动态类型语言,变量使用前不需要定义类型,在使用时直接赋值即可。 1 基本数据类型 值可以存储在变量中,作为参数传递或作为结果返回。 lua中有八个基本数据类型: nil 只有值nil属于该类,表示一个无效值&#…...
一文3000字从0到1使用pytest-xdist实现分布式APP自动化测试
目录 01、分布式测试的原理 02、测试项目 03、环境准备 04、搭建步骤 05、分布式执行 06、测试报告 不知道大家有没有遇到这样一种情况,实际工作中,app自动化测试的用例可能是成百上千条的,如果放在一台机器上跑,消耗的时间…...
React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...
让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...
数学建模-滑翔伞伞翼面积的设计,运动状态计算和优化 !
我们考虑滑翔伞的伞翼面积设计问题以及运动状态描述。滑翔伞的性能主要取决于伞翼面积、气动特性以及飞行员的重量。我们的目标是建立数学模型来描述滑翔伞的运动状态,并优化伞翼面积的设计。 一、问题分析 滑翔伞在飞行过程中受到重力、升力和阻力的作用。升力和阻力与伞翼面…...
【Linux手册】探秘系统世界:从用户交互到硬件底层的全链路工作之旅
目录 前言 操作系统与驱动程序 是什么,为什么 怎么做 system call 用户操作接口 总结 前言 日常生活中,我们在使用电子设备时,我们所输入执行的每一条指令最终大多都会作用到硬件上,比如下载一款软件最终会下载到硬盘上&am…...
GraphQL 实战篇:Apollo Client 配置与缓存
GraphQL 实战篇:Apollo Client 配置与缓存 上一篇:GraphQL 入门篇:基础查询语法 依旧和上一篇的笔记一样,主实操,没啥过多的细节讲解,代码具体在: https://github.com/GoldenaArcher/graphql…...
书籍“之“字形打印矩阵(8)0609
题目 给定一个矩阵matrix,按照"之"字形的方式打印这个矩阵,例如: 1 2 3 4 5 6 7 8 9 10 11 12 ”之“字形打印的结果为:1,…...
PH热榜 | 2025-06-08
1. Thiings 标语:一套超过1900个免费AI生成的3D图标集合 介绍:Thiings是一个不断扩展的免费AI生成3D图标库,目前已有超过1900个图标。你可以按照主题浏览,生成自己的图标,或者下载整个图标集。所有图标都可以在个人或…...
从零手写Java版本的LSM Tree (一):LSM Tree 概述
🔥 推荐一个高质量的Java LSM Tree开源项目! https://github.com/brianxiadong/java-lsm-tree java-lsm-tree 是一个从零实现的Log-Structured Merge Tree,专为高并发写入场景设计。 核心亮点: ⚡ 极致性能:写入速度超…...
JavaScript 标签加载
目录 JavaScript 标签加载script 标签的 async 和 defer 属性,分别代表什么,有什么区别1. 普通 script 标签2. async 属性3. defer 属性4. type"module"5. 各种加载方式的对比6. 使用建议 JavaScript 标签加载 script 标签的 async 和 defer …...
