news 2026/7/15 19:17:52

记一次 .NET 某注塑模具系统 CPU爆高分析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
记一次 .NET 某注塑模具系统 CPU爆高分析

讲故事

前些天有位朋友在微信上找到我,说他们的系统出现了CPU爆高,找不到原因,让我帮忙看一下,dump也拿出来了,接下来上windbg分析。

二:CPU爆高分析

1. 真的爆高吗

dump的分析第一原则就是相信数据,先使用!tp观察cpu使用率。

0:031> !tp Using the Portable thread pool. CPU utilization: 100% Workers Total: 5 Workers Running: 4 Workers Idle: 1 Worker Min Limit: 2 Worker Max Limit: 32767

从卦中可以看到CPU utilization=100%,说明确实被打满了,接下来我们看下 cpu 的 strength,使用!cpuid即可,参考如下:

0:031> !cpuid CP F/M/S Manufacturer MHz 0 6,85,7 <unavailable> 2993 1 6,85,7 <unavailable> 2993

这卦不看不知道,一看吓一跳,堂堂server端的程序居然只有2core, 这程序稍微痉挛一下必定cpu爆高,这上哪说理去,让马儿跑又不让马儿吃草。。。

接下来我们探究下到底是什么引发的cpu爆高,按照行业惯例,首先怀疑是不是gc导致的,最steady的方式就是使用命令~* k观察各个线程栈。

# 31 Id: 19e4.23e4 Suspend: 0 Teb: 00000063`6f12e000 Unfrozen ".NET TP Worker" # Child-SP RetAddr Call Site 00 00000063`041bef18 00007ffe`03a5d75e ntdll!NtWaitForSingleObject+0x14 01 00000063`041bef20 00007ffd`b87330fd KERNELBASE!WaitForSingleObjectEx+0x8e 02 (Inline Function) --------`-------- coreclr!GCEvent::Impl::Wait+0x13 [D:\a\_work\1\s\src\coreclr\gc\windows\gcenv.windows.cpp @ 1372] 03 (Inline Function) --------`-------- coreclr!GCEvent::Wait+0x13 [D:\a\_work\1\s\src\coreclr\gc\windows\gcenv.windows.cpp @ 1422] 04 00000063`041befc0 00007ffd`b8734bb2 coreclr!SVR::gc_heap::wait_for_gc_done+0x5d [D:\a\_work\1\s\src\coreclr\gc\gc.cpp @ 14979] 05 00000063`041beff0 00007ffd`b873311d coreclr!SVR::GCHeap::GarbageCollectGeneration+0xee [D:\a\_work\1\s\src\coreclr\gc\gc.cpp @ 50760] 06 00000063`041bf040 00007ffd`b882d6d8 coreclr!SVR::gc_heap::trigger_gc_for_alloc+0x15 [D:\a\_work\1\s\src\coreclr\gc\gc.cpp @ 19134] 07 00000063`041bf070 00007ffd`b87e0b70 coreclr!SVR::gc_heap::try_allocate_more_space+0x4ca20 [D:\a\_work\1\s\src\coreclr\gc\gc.cpp @ 19295] 08 00000063`041bf0e0 00007ffd`b87e0ae4 coreclr!SVR::gc_heap::allocate_more_space+0x68 [D:\a\_work\1\s\src\coreclr\gc\gc.cpp @ 19779] 09 00000063`041bf140 00007ffd`b8724e65 coreclr!SVR::gc_heap::allocate_uoh_object+0x58 [D:\a\_work\1\s\src\coreclr\gc\gc.cpp @ 45154] 0a 00000063`041bf1b0 00007ffd`b86eb239 coreclr!SVR::GCHeap::Alloc+0x1c5 [D:\a\_work\1\s\src\coreclr\gc\gc.cpp @ 49673] 0b 00000063`041bf200 00007ffd`b86edd6a coreclr!Alloc+0x99 [D:\a\_work\1\s\src\coreclr\vm\gchelpers.cpp @ 238] 0c (Inline Function) --------`-------- coreclr!AllocateSzArray+0x29b [D:\a\_work\1\s\src\coreclr\vm\gchelpers.cpp @ 428] 0d 00000063`041bf250 00007ffd`5be4394a coreclr!JIT_NewArr1+0x3ba [D:\a\_work\1\s\src\coreclr\vm\jithelpers.cpp @ 2800] 0e 00000063`041bf470 00007ffd`5bdbd7de Microsoft_Data_SqlClient!Microsoft.Data.SqlClient.TdsParser.TryReadSqlStringValue(Microsoft.Data.SqlClient.SqlBuffer, Byte, Int32, System.Text.Encoding, Boolean, Microsoft.Data.SqlClient.TdsParserStateObject)+0x17aa9ca [/_/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @ 5703] ... 17 00000063`041bfab0 00007ffd`b86ca02a coreclr!CallDescrWorkerInternal+0x83 [D:\a\_work\1\s\src\coreclr\vm\amd64\CallDescrWorkerAMD64.asm @ 100] 18 00000063`041bfaf0 00007ffd`b87eb116 coreclr!DispatchCallSimple+0x66 [D:\a\_work\1\s\src\coreclr\vm\callhelpers.cpp @ 221] 19 00000063`041bfb80 00007ffd`b86e2602 coreclr!ThreadNative::KickOffThread_Worker+0x66 [D:\a\_work\1\s\src\coreclr\vm\comsynchronizable.cpp @ 158] ... 21 00000063`041bfd90 00000000`00000000 ntdll!RtlUserThreadStart+0x2b

纵观卦中的各个调用栈,并没有看到触发的GC线程,只有一个coreclr!SVR::gc_heap::wait_for_gc_done,根据gc的知识,这是等待gc finish的操作,所以这个程序果然触发了GC。

2. 为什么会触发 GC

要想回答这个问题,需要知道GC触发的是哪一代,这是我们继续下去的重要突破口,接下来使用x coreclr!*settings*提取 settings 结构体,参考如下:

0:031> x coreclr!*settings* 00007ffd`b8b221b0 coreclr!SVR::gc_heap::settings = class SVR::gc_mechanisms 0:031> dx -r1 (*((coreclr!SVR::gc_mechanisms *)0x7ffdb8b221b0)) (*((coreclr!SVR::gc_mechanisms *)0x7ffdb8b221b0)) [Type: SVR::gc_mechanisms] [+0x000] gc_index : 0x2d3e [Type: unsigned __int64] [+0x008] condemned_generation : 2 [Type: int] [+0x00c] promotion : 1 [Type: int] [+0x010] compaction : 0 [Type: int] [+0x014] loh_compaction : 0 [Type: int] [+0x018] heap_expansion : 0 [Type: int] [+0x01c] concurrent : 0x0 [Type: unsigned int] [+0x020] demotion : 0 [Type: int] [+0x024] card_bundles : 1 [Type: int] [+0x028] gen0_reduction_count : 0 [Type: int] [+0x02c] should_lock_elevation : 0 [Type: int] [+0x030] elevation_locked_count : 0 [Type: int] [+0x034] elevation_reduced : 0 [Type: int] [+0x038] minimal_gc : 0 [Type: int] [+0x03c] reason : reason_alloc_loh (4) [Type: gc_reason] [+0x040] pause_mode : pause_interactive (1) [Type: SVR::gc_pause_mode] [+0x044] found_finalizers : 1 [Type: int] [+0x048] background_p : 0 [Type: int] [+0x04c] b_state : bgc_not_in_process (0) [Type: bgc_state] [+0x050] stress_induced : 0 [Type: int] [+0x054] entry_memory_load : 0x24 [Type: unsigned int] [+0x058] entry_available_physical_mem : 0x3d3d73000 [Type: unsigned __int64] [+0x060] exit_memory_load : 0x24 [Type: unsigned int]

从卦中的condemned_generation : 2reason : reason_alloc_loh来看,一切都明白了,然来这个 gc正在触发 fullgc,并且是因为 loh 的代边界满了,这个信息的潜台词就是告诉我们,有人在大概率折腾 LOH,接下来用!eeheap -gc切到大对象堆中去看看。

0:031> !eeheap -gc DATAS = ======================================== Number of GC Heaps: 2 ---------------------------------------- Large object heap segment begin allocated committed allocated size committed size ... 022f3f4fe4d0 01efdb000028 01efdf9ded80 01efdf9df000 0x49ded58 (77458776) 0x49df000 (77459456) 022f3f500750 01efe7000028 01efea8c86b8 01efea8e9000 0x38c8690 (59541136) 0x38e9000 (59674624) 022f3f501890 01efed000028 01eff22a05c0 01eff22a1000 0x52a0598 (86640024) 0x52a1000 (86642688) 022f3f504c50 01efff000028 01f004e6c1b8 01f004e8d000 0x5e6c190 (99008912) 0x5e8d000 (99143680) 022f3f508010 01f011000028 01f016620f68 01f016641000 0x5620f40 (90312512) 0x5641000 (90443776) 022f3f50a290 01f01d000028 01f0219ded80 01f0219df000 0x49ded58 (77458776) 0x49df000 (77459456) 022f3f50b3d0 01f023000028 01f023f1be28 01f023f3c000 0xf1be00 (15842816) 0xf3c000 (15974400) 022f3f513250 01f04f000028 01f0539ded80 01f0539df000 0x49ded58 (77458776) 0x49df000 (77459456) 022f3f5154d0 01f05b000028 01f05b000028 01f05f9df000 0x49df000 (77459456) 022f3f518890 01f06d000028 01f0719ded80 01f0719df000 0x49ded58 (77458776) 0x49df000 (77459456) 022f3f524650 01f0af000028 01f0b39ded80 01f0b39df000 0x49ded58 (77458776) 0x49df000 (77459456) ... Pinned object heap segment begin allocated committed allocated size committed size 022f3f4df200 01ef2d800028 01ef2d816d08 01ef2d821000 0x16ce0 (93408) 0x21000 (135168) ------------------------------ GC Allocated Heap Size: Size: 0xce96da90 (3465992848) bytes. GC Committed Heap Size: Size: 0x119465000 (4719005696) bytes.

从卦中看,大对象堆确实块头不小,接下来抽几个段出来看看。

0:031> !dumpheap 01efdb000028 01efdf9ded80 Address MT Size 01efdb000028 01ef2af58580 32 Free 01efdb000048 7ffd58de2a10 77,458,744 Statistics: MT Count TotalSize Class Name 01ef2af58580 1 32 Free 7ffd58de2a10 1 77,458,744 System.Char[] Total 2 objects, 77,458,776 bytes 0:031> !dumpheap 01f04f000028 01f0539ded80 Address MT Size 01f04f000028 01ef2af58580 32 Free 01f04f000048 7ffd58de2a10 77,458,744 Statistics: MT Count TotalSize Class Name 01ef2af58580 1 32 Free 7ffd58de2a10 1 77,458,744 System.Char[] Total 2 objects, 77,458,776 bytes

从卦中看确实也验证了我们的思路,里面有不少77M的 char[],如果胆大心细,你也能大概率猜到这个等待gc完成的线程应该也是在分配大对象,使用!dso观察便知。

0:031> !dso OS Thread Id: 0x23e4 (31) SP/REG Object Name 0063041bf198 01ef3607c610 Microsoft.Data.SqlClient.TdsParserStateObject+StateSnapshot 0063041bf200 01ef8fd2d128 System.Threading.ExecutionContext 0063041bf220 01ef2ff33390 Microsoft.Data.SqlClient.TdsParserStateObjectNative 0063041bf228 01ef8fd2d150 Microsoft.Data.SqlClient.TdsParserStateObject+StateSnapshot+PacketData 0063041bf268 01ef3607c610 Microsoft.Data.SqlClient.TdsParserStateObject+StateSnapshot 0063041bf278 01f06d000048 System.Char[] 0063041bf290 022fc03f2228 System.String 0063041bf298 01ef8fd2d150 Microsoft.Data.SqlClient.TdsParserStateObject+StateSnapshot+PacketData 0063041bf340 01ef8fd2cfe0 System.Threading.Tasks.TaskCompletionSource<System.Object> 0063041bf3c0 01ef3607b8c8 Microsoft.Data.SqlClient._SqlMetaData 0063041bf400 01ef2ff38e38 Microsoft.Data.SqlClient.SNIHandle 0063041bf438 01ef2ff33390 Microsoft.Data.SqlClient.TdsParserStateObjectNative 0063041bf450 01ef3607b8c8 Microsoft.Data.SqlClient._SqlMetaData 0063041bf460 01ef3607c290 Microsoft.Data.SqlClient.SqlBuffer 0063041bf470 01ef2ff33390 Microsoft.Data.SqlClient.TdsParserStateObjectNative 0063041bf480 01ef2ff33390 Microsoft.Data.SqlClient.TdsParserStateObjectNative 0063041bf4a8 01ef2ff33390 Microsoft.Data.SqlClient.TdsParserStateObjectNative 0063041bf4b0 01ef8fd21370 Microsoft.Data.SqlClient.TdsParserStateObject+StateSnapshot+PacketData 0063041bf528 01ef3607b8c8 Microsoft.Data.SqlClient._SqlMetaData

到这里基本上就知道了,是有人从数据库中捞取77M的大对象所致,接下来我们看下神秘的77M是什么,直接将内存导出到txt中,这里涉及到客户隐私,我们截张去敏的图,参考如下:

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/15 19:17:38

Docker--认识Docker网络

Network NamespaceNetwork Namespace 是Linux用于实现网络虚拟化的重要功能&#xff0c;他能创建多个隔离的网络空间&#xff0c;每个独立网络空间内的防火墙、网卡、路由表、邻居表、协议栈都是独立的。不管是虚拟机还是容器&#xff0c;当运行在独立的命名空间时&#xff0c;…

作者头像 李华
网站建设 2026/7/13 5:15:19

FMEA×控制计划×PPAP自动联动,这才是研发管理的天花板-全星研发项目管理APQP软件系统#APQP #PLM #汽车电子 #芯片研发 #新能源 #项目管理软件

FMEA控制计划PPAP自动联动&#xff0c;这才是研发管理的天花板-全星研发项目管理APQP软件系统 做汽车部件、芯片、新能源、新材料的研发人&#xff0c;是不是有这种感觉&#xff1a;通用PLM用起来各种别扭&#x1f92f; 文档管得了&#xff0c;流程控不住&#xff1b;BOM看得见…

作者头像 李华
网站建设 2026/7/13 5:15:43

MSP430 ADC模块深度解析:从寄存器配置到低功耗设计实战

1. ADC模块的核心价值与设计哲学在嵌入式系统设计的江湖里&#xff0c;ADC&#xff08;模数转换器&#xff09;模块的地位&#xff0c;就好比一个顶尖厨师手中的那把主厨刀。它不一定是系统里最复杂的部分&#xff0c;但绝对是决定最终“菜品”品质——也就是数据采集精度与可靠…

作者头像 李华
网站建设 2026/7/13 5:15:40

| LiveMoments 用参考图引导的扩散模型提升重选封面帧画质

常使用中&#xff0c;用户往往希望从这段视频中重新选择某一帧作为封面&#xff0c;以捕捉更理想的表情、动作或时机。然而&#xff0c;在实际使用中&#xff0c;问题也随之显现&#xff1a;由于视频本身分辨率低、压缩严重&#xff0c;重选的封面帧往往画质不足&#xff0c;难…

作者头像 李华
网站建设 2026/7/13 5:15:39

如何通过4个维度全面提升Windows系统性能?

如何通过4个维度全面提升Windows系统性能&#xff1f; 【免费下载链接】Winhance-zh_CN A Chinese version of Winhance. C# application designed to optimize and customize your Windows experience. 项目地址: https://gitcode.com/gh_mirrors/wi/Winhance-zh_CN 你…

作者头像 李华
网站建设 2026/7/13 5:15:38

从TPA3111D1评估板到自主设计:D类音频功放实战指南

1. 项目概述&#xff1a;从一块评估板到你的第一个D类功放设计如果你正在为一个小型音箱、便携式播放器或者任何需要紧凑、高效音频放大的项目寻找解决方案&#xff0c;那么D类音频放大器几乎是你绕不开的选择。而当你拿到一颗像德州仪器&#xff08;TI&#xff09;TPA3111D1这…

作者头像 李华