分析一个 .NET 写的 某 RFID标签系统 CPU暴涨

一:背景

1. 讲故事

前段时间有位朋友说他的程序 CPU 出现了暴涨现象,由于程序是买来的,所以问题就比较棘手了,那既然找到我,就想办法帮朋友找出来吧,分析下来,问题比较经典,有必要和大家做一下分享。

二:WinDbg 分析

1. CPU 真的爆高吗

一直关注这个系列的朋友应该知道,用 !tp 验证即可。

0:161> !tp
CPU utilization: 81%
Worker Thread: Total: 486 Running: 486 Idle: 0 MaxLimit: 8191 MinLimit: 24
Work Request in Queue: 0
--------------------------------------
Number of Timers: 1
--------------------------------------
Completion Port Thread:Total: 6 Free: 1 MaxFree: 48 CurrentLimit: 6 MaxLimit: 1000 MinLimit: 24

果然 CPU =81% ,并且当前的 481 个工作线程全部打满,以经验看可能是遇到锁什么的,不过还是先从是否触发 GC 看起。

2. 是触发 GC 了吗?

要查看是否触发 GC,可以用 !t -special 看看是否有 SuspendEE 字样。

0:161> !t -special
ThreadCount:      604
UnstartedThread:  0
BackgroundThread: 587
PendingThread:    0
DeadThread:       11
Hosted Runtime:   noOSID Special thread type29 2e74 DbgHelper 30 1014 GC SuspendEE 31 4a84 GC 32 4a48 GC ...52 37c0 GC 53 47a0 GC 54 4620 Finalizer 55 1aa4 ProfilingAPIAttach...

从卦中看,30号线程果然挂了 SuspendEE,并且还是一个 GC 线程,接下来切过去看看此时 GC 正在做什么?

0:161> ~~[1014]s
eax=00000000 ebx=0724fc10 ecx=00000000 edx=00000000 esi=00000000 edi=0724fc10
eip=77ddf02c esp=0724fbd0 ebp=0724fc34 iopl=0         nv up ei pl nz ac po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000212
ntdll!NtDelayExecution+0xc:
77ddf02c c20800          ret     8
0:030> k# ChildEBP RetAddr      
00 0724fc34 758345da     ntdll!NtDelayExecution+0xc
01 0724fc34 738a74eb     KERNELBASE!SleepEx+0x8a
02 0724fc78 73a0f710     clr!EESleepEx+0x59
03 0724fc78 73a0f809     clr!SVR::gc_heap::mark_steal+0x27c
04 0724fcd0 73a17930     clr!SVR::gc_heap::mark_phase+0x3d0
05 0724fd0c 73a17dc9     clr!SVR::gc_heap::gc1+0xf2
06 0724fd5c 73a174a1     clr!SVR::gc_heap::garbage_collect+0x746
07 0724fd78 73a10d7e     clr!SVR::gc_heap::gc_thread_function+0x14a
08 0724fd98 73a10d0f     clr!SVR::gc_heap::gc_thread_stub+0x72
09 0724fdac 750e62c4     clr!GCThreadStub+0x1f
0a 0724fdc0 77dd1f69     kernel32!BaseThreadInitThunk+0x24
0b 0724fe08 77dd1f34     ntdll!__RtlUserThreadStart+0x2f
0c 0724fe18 00000000     ntdll!_RtlUserThreadStart+0x1b

从卦中的 gc_thread_function 函数看,这是一个阻塞版的 GC 线程,当前正处于 mark_phase 标记阶段,并且还在抢其他 GC 线程的活,有点意思。。。

既然是触发了 GC ,那就看下触发了哪一代以及什么原因触发的。

0:030> x clr!*gc_heap::settings*
73f15da8          clr!WKS::gc_heap::settings = <no type information>
73f13520          clr!SVR::gc_heap::settings = <no type information>
0:030> dp 73f13520 
73f13520  00002df0 00000002 00000001 00000001
73f13530  00000000 00000000 00000000 00000000
73f13540  00000000 00000000 00000000 00000000
73f13550  00000000 00000000 00000005 00000001
73f13560  00000000 00000000 00000000 00000001
73f13570  00000000 0000005a 00000000 00000001
73f13580  05f71b40 86b2ee2e 00040000 00000001
73f13590  00000002 00002000 00000002 00000000

从卦中的 0000000200000005 可知,当前触发的是 2代 GC,原因是 5,那 5 是什么意思?可以看下 clr 中的 gc_reason 即可。

enum gc_reason
{reason_alloc_soh = 0,reason_induced = 1,reason_lowmemory = 2,reason_empty = 3,reason_alloc_loh = 4,reason_oos_soh = 5,reason_oos_loh = 6,reason_induced_noforce = 7, // it's an induced GC and doesn't have to be blocking.reason_gcstress = 8,        // this turns into reason_induced & gc_mechanisms.stress_induced = truereason_lowmemory_blocking = 9,reason_induced_compacting = 10,reason_lowmemory_host = 11,reason_pm_full_gc = 12, // provisional mode requested to trigger full GCreason_lowmemory_host_blocking = 13,reason_bgc_tuning_soh = 14,reason_bgc_tuning_loh = 15,reason_bgc_stepping = 16,reason_max
};

也就是上面的 reason_oos_soh,表示当前的小对象堆中的段空间满了,那是不是呢?可以用 !eeheap -gc 看下托管堆。

0:030> !eeheap -gc
Number of GC Heaps: 24
------------------------------
Heap 0 (06d00138)
generation 0 starts at 0xe8a380ec
generation 1 starts at 0xe8a380e0
generation 2 starts at 0x07311000
ephemeral segment allocation context: (0xe8a380f8, 0xe8a38104)segment     begin  allocated      size
07310000  07311000  0830fd5c  0xffed5c(16772444)
a86a0000  a86a1000  a969fd10  0xffed10(16772368)
e8a10000  e8a11000  e8a380f8  0x270f8(159992)
Large object heap starts at 0x1f311000segment     begin  allocated      size
1f310000  1f311000  1f4cafb0  0x1b9fb0(1810352)
Heap Size:       Size: 0x21deb14 (35515156) bytes.
------------------------------
...
Heap 22 (06d76910)
generation 0 starts at 0xbfd5d228
generation 1 starts at 0xbfd5ce20
generation 2 starts at 0x1d311000
ephemeral segment allocation context: (0xbfd5d234, 0xbfd5d240)segment     begin  allocated      size
1d310000  1d311000  1e30fe64  0xffee64(16772708)
bed60000  bed61000  bfd5d234  0xffc234(16761396)
Large object heap starts at 0x2a311000segment     begin  allocated      size
2a310000  2a311000  2a311010  0x10(16)
Heap Size:       Size: 0x1ffb0a8 (33534120) bytes.
...
------------------------------
GC Heap Size:    Size: 0x2f6f6d18 (795831576) bytes.

可以看到,heap 上很多都是 segment=16M  打满状态,停。。。为什么 segment 只有 16M ,出现了一个重大线索。

3. 重大线索解读

一个 Server 版的 GC,拥有高达 24 个逻辑核,居然只有 16M 的 segment,这么小的 segment,很容易被一些快进快出的大内存操作给打满,也就更容易造成 GC 触发,而且还是 Full GC,版本信息如下:

0:030> !eeversion
4.7.3416.0 retail
Server mode with 24 gc heaps
SOS Version: 4.7.3416.0 retail build

接下来到线程栈上找找有没有快进快出的大内存操作。

4. 寻找大内存操作

既然有快进快出的操作,在 GC 触发时肯定还会躺在 托管堆 上,我们就从这里入手。

0:030> !dumpheap -stat
Statistics:MT    Count    TotalSize Class Name
...
06cd1750   638727     15899642      Free
30361270   171401     19196912 xxxx.Entities.ProductInventoryLog
30360f90   537090     32225400 xxxx.Entities.ProductInventoryEpcDetail
30f9a148   171404     67875600 System.Data.Entity.Core.Objects.StateManagerValue[]
3036074c   694875     97282500 xxxx.Entities.ProductBorrow
727efd60  8419815    394836372 System.String
Total 14577631 objects
Fragmented blocks larger than 0.5 MB:Addr     Size      Followed by
9b0bf500    0.5MB         9b141878 System.Byte[]

从托管堆看,有不少的类对象,接下来抽一个 xxxx.Entities.ProductInventoryEpcDetail 看下引用,然后查根对象的 size。

0:161> !gcroot a8780ecc
Thread 40b8:df90d330 715d143a System.Linq.Enumerable+<JoinIterator>d__38`4[[System.__Canon, mscorlib],[System.__Canon, mscorlib],[System.__Canon, mscorlib],[System.__Canon, mscorlib]].MoveNext()esi: ->  090eeba4 System.Linq.Enumerable+<JoinIterator>d__38`4[]...->  a8780e80 xxxx.Entities.ProductInventoryEpcDetail[]->  a8780ecc xxxx.Entities.ProductInventoryEpcDetailFound 1 unique roots (run '!GCRoot -all' to see all roots).

其实这个引用链特别长,用 !objsize 090eeba4 显示对象大小,一直都是卡住中,size 肯定不小, 接下来我们切入到 40b8 看下这个方法,可以发现一个非常复杂的 EF 写法,又是 outer,又是 inner,又要再关联,截图如下:

51e95413b87b0fafb94ea2b0383906e2.png

到这里大对象操作终于找到了,我发现还有其他方法也有一些 EF 复杂操作,就不一一列举了。

三:总结

这个 dump 给我们两个教训:

  1. 当 sql 很复杂时,千万不要用 EF 去写,这中间会产生多少个临时对象你真的搞不清楚,你也hold不住,建议直接改成 sql,简单粗暴。

  2. 程序尽量用 64bit 部署,否则你的 segment 会太小,太容易让 GC 上头了。

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

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

相关文章

CentOS关机与重启命令详解

2019独角兽企业重金招聘Python工程师标准>>> Linux centos重启命令&#xff1a; 1、reboot  2、shutdown -r now 立刻重启(root用户使用)  3、shutdown -r 10 过10分钟自动重启(root用户使用)  4、shutdown -r 20:35 在时间为20:35时候重启(root用户使用)如果…

【ArcGIS微课1000例】0031:ArcGIS中的32个拓扑规则(图文详解)

在地理数据库中,拓扑是定义点要素、线要素以及面要素共享重叠几何的方式的排列布置。例如,街道中心线与人口普查区块共享公共几何,相邻的土壤面共享公共边界。学习拓扑就必须掌握ArcGIS中常见的拓扑规则。 文章目录 一、面的拓扑规则(10种)二、点的拓扑规则(6种)三、线的…

Blazor University (38)JavaScript 互操作 —— 从 .NET 调用 JavaScript

原文链接&#xff1a;https://blazor-university.com/javascript-interop/calling-javascript-from-dotnet/从 .NET 调用 JavaScriptJavaScript 应添加到服务器端 Blazor 应用程序的 /Pages/_Host.cshtml 或 Web Assembly Blazor 应用程序的 wwwroot/index.html 中。然后可以通…

十大排序总结(js实现、稳定性、内外部排序区别、时间空间复杂度、冒泡、快速、直接选择、堆、直接插入、希尔、桶、基数、归并、计数排序)

目录 排序相关概念 稳定性 内部排序 外部排序 十种排序算法特点总结 交换排序 冒泡排序&#xff08;数组sort方法的原理&#xff09; 图解 js实现 特点 快速排序 图解 js实现 特点 选择排序 直接选择排序 图解 js实现 特点 堆排序 大&#xff08;小&#xff0…

三维重建技术概述

基于视觉的三维重建&#xff0c;指的是通过摄像机获取场景物体的数据图像&#xff0c;并对此图像进行分析处理&#xff0c;再结合计算机视觉知识推导出现实环境中物体的三维信息。 1. 相关概念 &#xff08;1&#xff09;彩色图像与深度图像 彩色图像也叫作RGB图像&#xff0c;…

【ArcGIS微课1000例】0032:ArcGIS中河流(曲线)、湖泊(水体色)图例制作案例教程

河流作为线要素,在符号化的过程中使用的大多都是直线符号,但是为了能够在出图的使用表现形象的河流对象,就有了使用曲线表示河流图例的需求,湖泊亦是如此。本文讲解在ArcGIS中制作标准的河流和湖泊图例的完整教程。 文章目录 一、案例效果二、图例制作三、图例修改一、案例…

浅谈微信小程序对于房地产行业的影响

前几日&#xff0c;我们曾经整理过一篇文章是关于微信小程序对于在线旅游业的影响的一些反思&#xff08;浅谈微信小程序对OTA在线旅游市场的影响&#xff09;&#xff0c;近日由于生活工作的需要走访了一些房地产的住宅商品房&#xff0c;突然想到微信小程序对于房地产行业会有…

新型基础测绘与实景三维中国建设技术文件【1】名词解释

文章目录一、新型基础测绘 new fundamental surveying and mapping**二、实景三维 3D real scene**三、时空大数据平台 spatio-temporal big data platform**四、地理实体 geo-entity**五、基础地理实体 fundamental geo-entity**六、组合地理实体数据 combined geo-entity dat…

深入理解javascript原型和闭包

原文链接http://www.cnblogs.com/wangfupeng1988/p/3977924.html 对象是属性的集合。 function show(x) {console.log(typeof(x)); // undefinedconsole.log(typeof(10)); // numberconsole.log(typeof(abc)); // stringconsole.log(typeof(true)); // booleanconsole.lo…

薪资高压线

阅读本文大概需要5分钟。最近一名读者咨询一个问题&#xff1a;洋哥&#xff0c;最近公司有一名同事因为打探其他人薪资被开除了&#xff0c;为啥我们公司要把薪资设置为高压线。这是个好问题&#xff0c;解答完他的疑惑后想起了一年多前写过一篇&#xff0c;彼时读者还比较少&…

达摩院年终预测出炉:2022 十大科技趋势,AI for Science 高居榜首

作为“一所探索科技未知的研究院”&#xff0c;阿里巴巴达摩院成立至今已经四年了。 这四年来&#xff0c;达摩院秉持着“探索科技位置&#xff0c;以人类愿景为驱动力&#xff0c;开展基础科学和颠覆式技术创新研究”的原则与使命&#xff0c;在基础科研和硬科技发展上“遍地生…

chrome调试工具高级不完整使用指南(基础篇)

一、前言 本文记录的是作者在工作上面对chrome的一些使用和情况的分析分享&#xff0c;内容仅代表个人的观点。转发请注明出处(http://www.cnblogs.com/st-leslie/),谢谢合作 二、浏览器模块介绍 由于chrome浏览器一直在不断的进行更新迭代&#xff0c;会不断的新增功能&#x…

新型基础测绘与实景三维中国建设技术文件【2】基础地理实体分类、粒度及精度基本要求

《新型基础测绘体系建设试点技术大纲》指出&#xff0c;新型基础测绘将以“基础地理实体”为核心的成果模式创新为切入点&#xff0c;带动技术体系、生产组织体系和政策标准体系的全面创新&#xff0c;从而实现基础测绘高质量发展。 基础地理实体作为新型基础测绘产品体系的核心…

构建和实现单点登录解决方案(转载于IBMdeveloperWorks)

将一个开放源码的基于 Java 的身份验证组件集成进 Web 门户中 在现有的应用程序中实现单点登录解决方案&#xff08;single sign-on&#xff0c;SSO&#xff0c;即登录一次&#xff0c;就可以向所有网络资源验证用户的身份&#xff09;是非常困难的&#xff0c;但是在构建复杂的…

分享一个基于Abp 和Yarp 开发的API网关项目

这个项目起源于去年公司相要尝试用微服务构建项目,在网关的技术选型中,我们原本确认了ApiSix 网关,如果需要写网关插件需要基于Lua脚本去写,我和另外一个同事当时基于这个写了一个简单的插件,但是开发测试以及发布都很麻烦,而且使用Lua脚本作为插件的开发语言本身也不是我们强项…

罗振宇2022“时间的朋友”跨年演讲全文稿(pdf)

2021年12月31日20:30&#xff0c;五粮液成都金融城演艺中心&#xff0c;罗振宇“时间的朋友”跨年演讲如约而至。 罗胖曾发下大愿望&#xff1a;跨年演讲要连办二十年。今年是第七场&#xff0c;也是最特殊的一场&#xff0c;罗胖面对12000个空座位&#xff0c;用53个好故事&am…

08.LoT.UI 前后台通用框架分解系列之——多样的Tag选择器

LOT.UI分解系列汇总&#xff1a;http://www.cnblogs.com/dunitian/p/4822808.html#lotui LoT.UI开源地址如下&#xff1a;https://github.com/dunitian/LoTCodeBase/tree/master/LoTUI 这个必须说下&#xff0c;本来是用Bootstrap-Select做的&#xff0c;很漂亮&#xff0c;正好…

jquery文档加载完毕后执行的几种写法

2019独角兽企业重金招聘Python工程师标准>>> 1.js文档加载完毕 标签内 οnlοad"test()"window.οnlοadfunction(){}2.jquery文档加载完毕 //方式1 $(document).ready(function(){//TODO }); //方式2 $(function(){//TODO }) //方式3 $(function($){//TO…

新型基础测绘与实景三维中国建设技术文件【3】基础地理实体空间身份编码规则

基础地理实体是新型基础测绘产品体系中的核心成果&#xff0c;是推动基础测绘工作转型升级的关键。与现有的测绘地理信息数据不同&#xff0c;基础地理实体具有多粒度、多模态、多层次&#xff0c;以及搭载结构化、半结构化和非结构化多样化信息的鲜明特点。 基础地理实体空间…

oracle 表 视图 存储过程 序列 job

table 表--delete tabledrop table Test1;-- Create tablecreate table TEST1(ID NUMBER,T_NAME VARCHAR2(100),DT DATE);-- 添加注释comment on column TEST1.T_NAME is 名称;--添加age字段alter table Test1 add (age NUMBER(8));--删除字段alter table TABLE_NAME …