记一次 .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(); 操作,也就每次都会创建程序集,终于真相大白。

三:总结

这种程序集泄露导致的生产事故不应该哈,反应了团队中多人协作的时候还是有待提高!

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

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

相关文章

Java基础(二)

1. 面向对象基础 1.1 面向对象和面向过程的区别 面向过程把解决问题的过程拆成一个个方法&#xff0c;通过一个个方法的执行解决问题。面向对象会先抽象出对象&#xff0c;然后用对象执行方法的方式解决问题。 面向对象开发的方式更容易维护和迭代升级、易复用、易扩展。 1…

3D孪生场景搭建:参数化模型

1、什么是参数化模型 参数化模型是指通过一组参数来定义其形状和特征的数学模型或几何模型。这些参数可以用于控制模型的大小、形状、比例、位置、旋转、曲率等属性&#xff0c;从而实现对模型进行灵活的调整和变形。 在计算机图形学和三维建模领域&#xff0c;常见的参数化模…

Docker 镜像的缓存特性

Author&#xff1a;rab 目录 前言一、构建缓存二、Pull 缓存总结 前言 首先我们要清楚&#xff0c;Docker 的镜像结构是分层的&#xff0c;镜像本身是只读的&#xff08;不管任何一层&#xff09;&#xff0c;当我们基于某镜像运行一个容器时&#xff0c;会有一个新的可写层被…

Springboot 音乐网站管理系统idea开发mysql数据库web结构java编程计算机网页源码maven项目

一、源码特点 springboot 音乐网站管理系统是一套完善的信息系统&#xff0c;结合springboot框架和bootstrap完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用springboot框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统 具有完整的源代码和数据库&…

让丢失成为过去,尽在我们的智能防丢器

我们都知道&#xff0c;生活中总会遇到一些小烦恼&#xff0c;比如钥匙不见了&#xff0c;钱包忘在哪里&#xff0c;甚至手机掉在了不知名的地方&#xff0c;这些看似小事&#xff0c;却足以打乱我们的日程。那么&#xff0c;有没有一种方法&#xff0c;可以让这些烦恼一扫而空…

一座“城池”:泡泡玛特主题乐园背后,IP梦想照亮现实

“更适合中国宝宝体质”的主题乐园&#xff0c;被泡泡玛特造出来了。 9月26日&#xff0c;位于北京朝阳公园内的国内首个潮玩行业沉浸式 IP 主题乐园&#xff0c;也是泡泡玛特首个线下乐园——泡泡玛特城市乐园 POP LAND正式开园。 约4万平方米的空间中&#xff0c;泡泡玛特使…

Javascript - 轮播图

轮播图也称banner图、广告图、焦点图、滑片。是指在一个模块或者窗口,通过鼠标点击或手指滑动后,可以看到多张图片。这些图片统称为轮播图,这个模块叫做轮播模块。可以通过运用 javascript去实现定时自动转换图片。以下通过一个小Demo演示如何运用Javascript实现。 <!DOCTYP…

winform中DevExpress控件一些属性

1.DevExpress控件bar去掉前面四点和后面的倒三角。 如图。设置bar属性optionsBar→allowQuickCustomizationFALSE

练[WUSTCTF2020]朴实无华

[WUSTCTF2020]朴实无华 文章目录 [WUSTCTF2020]朴实无华掌握知识解题思路代码分析 关键paylaod 掌握知识 ​ 目录扫描&#xff0c;抓包放包&#xff0c;代码审计&#xff0c;php函数特性的了解&#xff1a;intval函数&#xff0c;md5特性绕过&#xff0c;RCE一些bypass方法 解…

测试老鸟总结,Jmeter接口测试实例-签名接口,一文彻底打通...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、签名规则 1&a…

3分钟带你认识腾讯云服务器CVM_一看就懂

腾讯云服务器CVM提供安全可靠的弹性计算服务&#xff0c;腾讯云明星级云服务器&#xff0c;弹性计算实时扩展或缩减计算资源&#xff0c;支持包年包月、按量计费和竞价实例计费模式&#xff0c;CVM提供多种CPU、内存、硬盘和带宽可以灵活调整的实例规格&#xff0c;提供9个9的数…

多个excel合并

目的&#xff1a;将同一个文件下的多个 “京东差评.xlsx” 合并为一个&#xff1a;“京东汇总.xlsx" 代码如下&#xff1a; # -*- coding: utf-8 -*- """ Created on Wed Oct 4 12:52:32 2023author: 64884 """import pandas as pd impor…

开发工具:推荐几款非常漂亮的VScode主题

目录 Atom One Dark Theme Github Theme Night Owl Theme Night Owl JellyFish Theme Sublime Material Theme 深色 浅色 今天给大家推荐几款非常漂亮的VScode主题&#xff0c;值得收藏&#xff01; Atom One Dark Theme 它是市场上最好的深色主题之一。Atom 标志性的…

前端笔试题总结,带答案和解析(二)

前端笔试题总结&#xff0c;带答案和解析&#xff08;二&#xff09; 这个系列将持续更新前端笔试题一期十题&#xff0c;每五题做一个标题&#xff08;方便跳转&#xff09;&#xff0c;您可以一期一期阅读&#xff0c;也可以在点击汇总&#xff0c;一口气看完&#xff0c;如果…

C/C++学习 -- SHA-256算法

SHA-256算法概述 SHA-256代表"Secure Hash Algorithm 256-bit"&#xff0c;是一种安全的哈希算法&#xff0c;输出固定长度的256位&#xff08;32字节&#xff09;哈希值。SHA-256被广泛用于加密、数字签名、密码学以及区块链等领域&#xff0c;因为它提供了高度的安…

详解Python的装饰器(多层语法糖、装饰器和装饰器修复技术及递归函数)

python中的装饰器(decorator)一般采用语法糖的形式&#xff0c;是一种语法格式。比如&#xff1a;classmethod&#xff0c;staticmethod&#xff0c;property&#xff0c;xxx.setter&#xff0c;wraps()&#xff0c;func_name等都是python中的装饰器。 装饰器&#xff0c;装饰的…

pytorch_神经网络构建2(数学原理)

文章目录 深层神经网络多分类深层网络反向传播算法优化算法动量算法Adam 算法 深层神经网络 分类基础理论: 交叉熵是信息论中用来衡量两个分布相似性的一种量化方式 之前讲述二分类的loss函数时我们使用公式-(y*log(y_)(1-y)*log(1-y_)进行概率计算 y表示真实值,y_表示预测值 …

【Pinia】小菠萝详细使用说明

文章目录 1. 介绍1.1 Pinia介绍1.2 pinia的属性说明 2. 安装3. 初步使用4. store具体使用4.1 值修改4.2.1 直接修改4.2.2 通过$patch整体修改4.2.3 通过$patch函数式4.2.4 通过$state整体修改4.2.5 通过actions修改 4.2 解构store 5 actions使用6. getters使用6.1 通过this获取…

Java Collection

Collection接口常用方法 ①添加&#xff1a; ​ add(Object obj):只要是对象都可以添加 ​ addAll(Collection c)&#xff1a;添加另一个集合的元素 ②删除&#xff1a; ​ clear():清空集合元素 ​ remove(Object obj)删除某个元素对象 ​ removeAll(Collection c)&…

熔断、限流、降级 —— SpringCloud Alibaba Sentinel

Sentinel 简介 Sentinel 是阿里中间件团队开源的&#xff0c;面向分布式服务架构的高可用流量防护组件&#xff0c;主要以流量为切入点&#xff0c;从限流、流量整形、熔断降级、系统负载保护、热点防护等多个维度来帮助开发者保障微服务的稳定性 Sentinel 提供了两个服务组件…