记一次 .NET 某物流API系统 CPU爆高分析
一:背景
1. 讲故事
前段时间有位朋友找到我,说他程序CPU直接被打满了,让我帮忙看下怎么回事,截图如下:

看了下是两个相同的程序,既然被打满了那就抓一个 dump 看看到底咋回事。
二:为什么会打满
1. 真的被打满了吗
凡事都要用数据说话,我们使用 !tp 命令观察一下。
0:014> !tp
logStart: 62
logSize: 200
CPU utilization: 100 %
Worker Thread: Total: 16 Running: 0 Idle: 16 MaxLimit: 32767 MinLimit: 8
Work Request in Queue: 0
--------------------------------------
Number of Timers: 8
--------------------------------------
Completion Port Thread:Total: 9 Free: 2 MaxFree: 16 CurrentLimit: 9 MaxLimit: 1000 MinLimit: 8
从卦象看果然是被打满了,那为什么会满呢?一般来说CPU高是线程抬起来的,接下来我们就从线程入手。
2. 线程都在做什么事情
要想观察每个线程都在做什么,可以使用 ~*e !clrstack 命令,打完所有的线程栈后,明显发现有 6 处在 System.Text.RegularExpressions.RegexReplacement.Replace 正则替换这里,截图如下:

0:021> ~14s
ntdll!NtWaitForSingleObject+0x14:
00007ff9`c5d4fa74 c3 ret
0:014> !clrstack
OS Thread Id: 0x6ee0 (14)Child SP IP Call Site
000000AC6CBF99C8 00007ff9c5d4fa74 [HelperMethodFrame: 000000ac6cbf99c8]
000000AC6CBF9AC0 00007ff942416c05 System.String.Create[[System.Text.SegmentStringBuilder, System.Text.RegularExpressions]](Int32, System.Text.SegmentStringBuilder, System.Buffers.SpanAction`2<Char,System.Text.SegmentStringBuilder>)
000000AC6CBF9B20 00007ff942416aeb System.Text.SegmentStringBuilder.ToString()
000000AC6CBF9BA0 00007ff9422e62ac System.Text.RegularExpressions.RegexReplacement.Replace(System.Text.RegularExpressions.Regex, System.String, Int32, Int32)
000000AC6CBF9C70 00007ff9422e4ec6 System.Text.RegularExpressions.Regex.Replace(System.String, System.String, System.String, System.Text.RegularExpressions.RegexOptions)
000000AC6CBF9CD0 00007ff941e157aa SqlSugar.UtilMethods.ReplaceSqlParameter(System.String, SqlSugar.SugarParameter, System.String)
000000AC6CBF9F80 00007ff941e42990 SqlSugar.SqlSugarProvider+d__245`1[[System.Int32, System.Private.CoreLib]].MoveNext()
000000AC6CBFA300 00007ff94190e93c System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[[System.__Canon, System.Private.CoreLib]](System.__Canon ByRef)
000000AC6CBFA360 00007ff941e420bd SqlSugar.SqlSugarProvider.SaveQueuesProviderAsync[[System.Int32, System.Private.CoreLib]](Boolean, System.Func`3<System.String,System.Collections.Generic.List`1<SqlSugar.SugarParameter>,System.Threading.Tasks.Task`1>)
000000AC6CBFA3D0 00007ff941e41a52 SqlSugar.SqlSugarProvider+d__224.MoveNext()
000000AC6CBFA480 00007ff94190e93c System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[[System.__Canon, System.Private.CoreLib]](System.__Canon ByRef)
000000AC6CBFA4E0 00007ff941e418f4 SqlSugar.SqlSugarProvider.SaveQueuesAsync(Boolean)
000000AC6CBFA550 00007ff941e417fe SqlSugar.SqlSugarClient.SaveQueuesAsync(Boolean)
000000AC6CBFA5A0 00007ff941e4177e SqlSugar.SqlSugarScope.SaveQueuesAsync(Boolean)
000000AC6CBFA5F0 00007ff941e40fce xxx.Repository.BaseRepository`1+d__76[[System.__Canon, System.Private.CoreLib]].MoveNext()
...
000000AC6D4FAAF0 00007ff9422c9d0c xxx.xxxService+d__15.MoveNext()
...
从上面的 MoveNext 和 AsyncMethodBuilder 来看,这里用的是全异步写法,分析起来那是一个头大哈。。。不过仔细观察是 SqlSugar 在替换sql参数的时候引发的,一般来说和 Regular 有关的操作都是蛮耗 CPU 的,然后顺手看了下cpu配置也才 8 核,难怪 CPU 直接 100% 了。
0:014> !cpuid
CP F/M/S Manufacturer MHz0 6,85,7 <unavailable> 25001 6,85,7 <unavailable> 25002 6,85,7 <unavailable> 25003 6,85,7 <unavailable> 25004 6,85,7 <unavailable> 25005 6,85,7 <unavailable> 25006 6,85,7 <unavailable> 25007 6,85,7 <unavailable> 2500
3. SqlSugar 到底在做什么
要想知道做什么,逆向一下代码就好,截图如下:

这种写法好不好我就不评价了,至少简单粗暴,那为什么会很耗时呢?这就要扒一下 ReplaceSqlParameter 方法中的三个参数,尤其是 itemSql 字段,然后使用 !clrstack -a。
0:014> !clrstack -a
OS Thread Id: 0x6ee0 (14)Child SP IP Call Site
000000AC6CBF9CD0 00007ff941e157aa SqlSugar.UtilMethods.ReplaceSqlParameter(System.String, SqlSugar.SugarParameter, System.String)PARAMETERS:itemSql (0x000000AC6CBF9F80) = 0x0000023d802e1020itemParameter (0x000000AC6CBF9F88) = 0x0000023c4bd3ae58newName (0x000000AC6CBF9F90) = 0x0000023ca9dd3328LOCALS:0x000000AC6CBF9F68 = 0x00000000000000000:014> !do 0x0000023d802e1020
Name: System.String
MethodTable: 00007ff93caad698
EEClass: 00007ff93ca89d60
Tracked Type: false
Size: 21391508(0x1466894) bytes
File: C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.12\System.Private.CoreLib.dll
String: <String is invalid or too large to print>Fields:MT Field Offset Type VT Attr Value Name
00007ff93ca99480 40002f2 8 System.Int32 1 instance 10695743 _stringLength
00007ff93c9fea10 40002f3 c System.Char 1 instance 49 _firstChar
00007ff93caad698 40002f1 e8 System.String 0 static 0000023c3f5613a0 Empty0:014> ?0n21391508 /0x400
Evaluate expression: 20890 = 00000000`0000519a
从卦中看,简直是吓一跳,这个 sql 居然高达 20M,🐂👃,难怪处理起来比较慢,很好奇这 20M 到底是个啥?我估计 SqlSugar 也没考虑到有这么大的 SQL 吧,那如何导出这 20M 数据呢?可以使用 .writemem 即可。
0:014> .writemem D:\testdump\1.txt 0x0000023d802e1020+0xc L?0x1466894
Writing 1466894 bytes......
这里稍微提醒下,大文本最好用 LogView 这种便捷工具,然后使用 Utf-16 的方式打开,截图如下:

看卦中信息看,应该是 batch insert 的时候 SqlSugar 在替换参数,在正则上出不来,那到底是 SqlSugar考虑不周还是使用者问题 ?
4. 到底是谁的问题
要想知道是谁的问题就需要看下是什么操作引发的批量提交,我们回头仔细研读下调用栈,通过逆向 xxx.xxxService+d__15.MoveNext 方法,简化后的逻辑如下:
public async Task<bool> Savexxx(xxxRequest requestModel){List<xxxDetailModel> list = new List<xxxDetailModel>();for (int i = 0; i < requestModel.xxxDetailList.Length; i++){_xxxService.AddQueue(list); //5w}return await _xxxService.SaveQueuesAsync() > 0;}
在 _xxxService.SaveQueuesAsync 的内部就是通过 SqlSugarProvider 进行的批量提交,接下来的问题是 list 到底有多少记录呢?
0:021> !dso
OS Thread Id: 0x51f8 (21)SP/REG Object Name00ac6cefae38 023c73d9c8a8 System.Collections.Generic.List<xxx.xxxDetailModel>
0:021> !do 023c73d9c8a8
Name: System.Collections.Generic.List`1[[xxx.xxxDetailModel]]
MethodTable: 00007ff93e12a2f8
EEClass: 00007ff93cb65668
Tracked Type: false
Size: 32(0x20) bytes
File: C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.12\System.Private.CoreLib.dll
Fields:MT Field Offset Type VT Attr Value Name
00007ff93cc6d000 4002095 8 System.__Canon[] 0 instance 0000023c52b36f18 _items
00007ff93ca99480 4002096 10 System.Int32 1 instance 30708 _size
00007ff93ca99480 4002097 14 System.Int32 1 instance 30708 _version
00007ff93cc6d000 4002098 8 System.__Canon[] 0 static dynamic statics NYI s_emptyArray
从卦中看当前是 3w 多,我发现在其他线程中也有 6w 的,比如下面这个。
0:014> !dumpobj /d 23c49e90300
Name: System.Collections.Generic.List`1[[xxx.xxxDetailModel]]
MethodTable: 00007ff93e12a2f8
EEClass: 00007ff93cb65668
Tracked Type: false
Size: 32(0x20) bytes
File: C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.12\System.Private.CoreLib.dll
Fields:MT Field Offset Type VT Attr Value Name
00007ff93cc6d000 4002095 8 System.__Canon[] 0 instance 0000023c1042fca8 _items
00007ff93ca99480 4002096 10 System.Int32 1 instance 63532 _size
00007ff93ca99480 4002097 14 System.Int32 1 instance 63532 _version
00007ff93cc6d000 4002098 8 System.__Canon[] 0 static dynamic statics NYI s_emptyArray
有了这些前因后果,建议朋友一次性少提交一点,比如 5000 条一次观察下效果如何。
三:总结
这次CPU爆高事故,主要还是因为 批量提交记录多 导致 SqlSugar 在做参数的正则替换上耗费了大量CPU时间所致,降低批量条数,通过小步快跑的方式尽可能的降低运行线程的积压,应该就能解决这个问题。
相关文章:
记一次 .NET 某物流API系统 CPU爆高分析
一:背景 1. 讲故事 前段时间有位朋友找到我,说他程序CPU直接被打满了,让我帮忙看下怎么回事,截图如下: 看了下是两个相同的程序,既然被打满了那就抓一个 dump 看看到底咋回事。 二:为什么会打…...
【Docker】Docker安装Kibana服务_Docker+Elasticsearch+Kibana
文章目录 1. 什么是Kibana2. Docker安装Kibana2.1. 前提2.2. 安装Kibana 点击跳转:Docker安装MySQL、Redis、RabbitMQ、Elasticsearch、Nacos等常见服务全套(质量有保证,内容详情) 1. 什么是Kibana Kibana 是一款适用于Elasticse…...
前端面试题-VUE
1. 对于MVVM的理解 MVVM 是 Model-View-ViewModel 的缩写Model 代表数据模型,也可以在 Model 中定义数据修改和操作的业务逻辑。View 代表 UI 组件,它负责将数据模型转化成 UI 展现出来。ViewModel 监听模型数据的改变和控制视图⾏为、处理⽤户交互&…...
Linux嵌入式平台安全启动理解介绍
一、意义 安全启动可以防止未授权的或是进行恶意篡改的软件在系统上运行,是系统安全的保护石,每一级的前一个镜像会对该镜像进行校验。 1.1 安全启动原理介绍 通过数字签名进行镜像完整性验证(使用到非对称加密算法和哈希算法) 签名过程: raw_image--->use ha…...
安全学习DAY09_加密逆向,特征识别
算法逆向&加密算法分类,特征识别 文章目录 算法逆向&加密算法分类,特征识别算法概念,分类单向散列加密 - MD5对称加密 - AES非对称加密 - RSA 常见加密算法识别特征,解密特点MD5密文特点BASE64编码特点AES、DES特点RSA密文…...
原型模式(Prototype)
原型模式是一种创建型设计模式,使调用方能够复制已有对象,而又无需使代码依赖它们所属的类。当有一个类的实例(原型),并且想通过复制原型来创建新对象时,通常会使用原型模式。 The Prototype pattern is g…...
深度学习之用PyTorch实现线性回归
代码 # 调用库 import torch# 数据准备 x_data torch.Tensor([[1.0], [2.0], [3.0]]) # 训练集输入值 y_data torch.Tensor([[2.0], [4.0], [6.0]]) # 训练集输出值# 定义线性回归模型 class LinearModel(torch.nn.Module):def __init__(self):super(LinearModel, self)._…...
45.248.11.X服务器防火墙是什么,具有什么作用
防火墙是一种网络安全设备或软件,服务器防火墙的作用主要是在服务器和外部网络之间起到一个安全屏障的作用,保护计算机网络免受未经授权的访问、恶意攻击或不良网络流量的影响,保护服务器免受恶意攻击和非法访问。它具有以下功能:…...
如何以无服务器方式运行 Go 应用程序
Go编程语言一直以来都对构建REST API提供了丰富的支持。这包括一个出色的标准库(net/HTTP),以及许多流行的包,如Gorilla mux、Gin、Negroni、Echo、Fiber等。使用AWS Lambda Go运行时,我们可以使用Go构建AWS Lambda函数…...
小程序商城系统的开发方式及优缺点分析
小程序商城系统是一种新型的电子商务平台,它通过小程序的形式为商家提供了一种全新的销售渠道,同时也为消费者提供了一种便捷的购物体验。小程序商城系统具有低成本、快速上线、易于维护等特点,因此在市场上受到了广泛的关注和应用。这里就小…...
[数据集][目标检测]城市道路井盖破损丢失目标检测1377张
数据集制作单位:未来自主研究中心(FIRC) 数据集格式:Pascal VOC格式(不包含分割路径的txt文件和yolo格式的txt文件,仅仅包含jpg图片和对应的xml) 图片数量(jpg文件个数):1377 标注数量(xml文件个数):1377 标注类别数&a…...
【Spring Cloud 三】Eureka服务注册与服务发现
系列文章目录 【Spring Cloud一】微服务基本知识 Eureka服务注册与服务发现 系列文章目录前言一、什么是Eureka?二、为什么要有服务注册发现中心?三、Eureka的特性四、搭建Eureka单机版4.1Eureka服务端项目代码pom文件配置文件启动类启动项目查看效果 E…...
WPF实战学习笔记21-自定义首页添加对话服务
自定义首页添加对话服务 定义接口与实现 添加自定义添加对话框接口 添加文件:Mytodo.Dialog.IDialogHostAware.cs using Prism.Commands; using Prism.Services.Dialogs; using System; using System.Collections.Generic; using System.Linq; using System.Tex…...
AngularJS学习(一)
目录 1. 引入 AngularJS2. 创建一个 AngularJS 应用3. 控制器(Controller)4. 模型(Model)5. 视图(View)6. 指令(Directive)7. 过滤器(Filter)8. 服务…...
918. 环形子数组的最大和
918. 环形子数组的最大和 给定一个长度为 n 的环形整数数组 nums ,返回 nums 的非空 子数组 的最大可能和 。 环形数组 意味着数组的末端将会与开头相连呈环状。形式上, nums[i] 的下一个元素是 nums[(i 1) % n] , nums[i] 的前一个元素是…...
AI算法图形化编程加持|OPT(奥普特)智能相机轻松适应各类检测任务
OPT(奥普特)基于SciVision视觉开发包,全新推出多功能一体化智能相机,采用图形化编程设计,操作简单、易用;不仅有上百种视觉检测算法加持,还支持深度学习功能,能轻松应对计数、定位、…...
C语言文件指针设置偏移量--fseek
一、fseek fseek是设置文件指针偏移量的函数,具体传参格式为: int fseek(FILE *stream, long int offset, int whence) 返回一个整数,其中: 1、stream是指向文件的指针 2、offset是偏移量,一般是指相对于whence的便…...
快速消除视频的原声的技巧分享
网络上下载的视频都会有视频原声或者背景音乐,如果不喜欢并且想更换新的BGM要怎么操作呢?今天小编就来教你如何快速给多个视频更换新的BGM,很简单,只需要将原视频的原声快速消音同时添加新的背景音频就行,一起来看看详…...
lua脚本实现Redis令牌桶限流
背景 令牌桶限流是一种常见的流量控制算法,用于控制系统的请求处理速率,防止系统过载。在令牌桶限流算法中,可以将请求看作是令牌,而令牌桶则表示系统的处理能力。系统在处理请求时,首先需要从令牌桶中获取令牌&#…...
最新 23 届计算机校招薪资汇总
24 届的秋招提前批已经开始了,比如米哈游、oppoe、tplink 等公司都已经录取开启提前批。 像腾讯、字节、阿里等一线大厂的话,根据往年的情况,估计是 7月下-8 月初。 所以今年参加秋招的同学,要抓紧复习了。 提前批通常就持续不到…...
【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...
2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...
docker 部署发现spring.profiles.active 问题
报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
Linux 内存管理实战精讲:核心原理与面试常考点全解析
Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...
CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!
本文介绍了一种名为AnomalyAny的创新框架,该方法利用Stable Diffusion的强大生成能力,仅需单个正常样本和文本描述,即可生成逼真且多样化的异常样本,有效解决了视觉异常检测中异常样本稀缺的难题,为工业质检、医疗影像…...
redis和redission的区别
Redis 和 Redisson 是两个密切相关但又本质不同的技术,它们扮演着完全不同的角色: Redis: 内存数据库/数据结构存储 本质: 它是一个开源的、高性能的、基于内存的 键值存储数据库。它也可以将数据持久化到磁盘。 核心功能: 提供丰…...
Java设计模式:责任链模式
一、什么是责任链模式? 责任链模式(Chain of Responsibility Pattern) 是一种 行为型设计模式,它通过将请求沿着一条处理链传递,直到某个对象处理它为止。这种模式的核心思想是 解耦请求的发送者和接收者,…...
第22节 Node.js JXcore 打包
Node.js是一个开放源代码、跨平台的、用于服务器端和网络应用的运行环境。 JXcore是一个支持多线程的 Node.js 发行版本,基本不需要对你现有的代码做任何改动就可以直接线程安全地以多线程运行。 本文主要介绍JXcore的打包功能。 JXcore 安装 下载JXcore安装包&a…...
el-amap-bezier-curve运用及线弧度设置
文章目录 简介示例线弧度属性主要弧度相关属性其他相关样式属性完整示例链接简介 el-amap-bezier-curve 是 Vue-Amap 组件库中的一个组件,用于在 高德地图 上绘制贝塞尔曲线。 基本用法属性path定义曲线的路径,可以是多个弧线段的组合。stroke-weight线条的宽度。stroke…...
