记一次 .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自动化测试的用例可能是成百上千条的,如果放在一台机器上跑,消耗的时间…...

地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...

遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...

如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...

视频字幕质量评估的大规模细粒度基准
大家读完觉得有帮助记得关注和点赞!!! 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用,因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型(VLMs)在字幕生成方面…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...
NPOI操作EXCEL文件 ——CAD C# 二次开发
缺点:dll.版本容易加载错误。CAD加载插件时,没有加载所有类库。插件运行过程中用到某个类库,会从CAD的安装目录找,找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库,就用插件程序加载进…...