一次.net code中的placeholder导致的高cpu诊断
背景
最近一位朋友找到我,让我帮看他们的一个aspnet core service无端cpu高的问题。从描述上看,这个service之前没有出现过cpu高的情况,最近也没有改过实际的什么code。很奇怪了,会有什么变化导致cpu上去了呢?
分析
由于比较容易复现 (据说一启动service,cpu就上去了),我便让那位朋友在cpu高的时候直接手动把.net进程dump了一下。于是就开始用windbg分析了
先看一下案发时进程中的线程情况,毕竟它们是让进程动起来的源泉哈。大部分线程都运行到如下类似位置(下面的callstack是虚拟化的,因为为了朋友的隐私,code已经虚拟化):

这里可以看出有约38/2=19个线程运行到Services.CronJob+d__1.MoveNext这个位置。我又问了那位朋友,当时的运行环境是大约20个cpu core。真巧哈,几乎所有cpu core都很有可能跑到了这个地方了。
注:上面如何知道有38/2个线程,而不是38个线程呢?这是因为一般来说,当某个函数正在被调用时,callstack中会显示出两次,如图哈:

看到没,在"current frame"下面显示的上一层调用关系中会也显示这个方法,此时它是callee哈。
那么这个Services.CronJob+d__1.MoveNext是何方神圣呢,名字叫cpu killer更贴切吧?
跑题了,去看看这个方法的代码。注意到这个是compiler generated code,所以就先看看generated code长啥样吧:
先利用上图中透露出来的method的md地址,用!dumpmd看一下这个方法的信息:

反编译看一下:

天啦撸,这好像是async state machine code,没事凑合看吧仔细观察那些标红的位置后,我发现这里面有些蹊跷啊。如果schedules不是null的话,有两种情况,这两种情况最终都会到label_10的地方,在那里,cpu可以得到休息;但如果schedules是null的话,会不会一直以同步的方式高速循环在while里?我在所有threads的stack上找寻,找不到有类型为List<string>的instance被stack引用着,所以很有可能是这个原因了。
另外,从Services.CronJob+d__1.MoveNext这个名字看,这个closure应该是在user code class CronJob中生成的,我们去看看。用!dumpheap:

正好19个CronJob, 这和刚分析的有19个线程正高速运行吻合。因为心情不错,所以再去看看CronJob的样子吧:
看起来这个CronJob是个long running的IHostedService,在循环中有的flow没有让thread休息导致cpu上来了。
后记
1 protected override async Task ExecuteAsync(CancellationToken stoppingToken)
2 {
3 await InitializeJobAsync();
4
5 while (!stoppingToken.IsCancellationRequested)
6 {
7 List<string>? schedules = PreferenceService.GetSchedules(Region);
8 if (schedules == null)
9 {
10
11 }
12 else
13 {
14 await ProcessJobAsync(schedules);
15 await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken);
16 }
17 }
18 }
1 protected override async Task ExecuteAsync(CancellationToken stoppingToken)
2 {
3 await InitializeJobAsync();
4
5 while (!stoppingToken.IsCancellationRequested)
6 {
7 List<string>? schedules = PreferenceService.GetSchedules(Region);
8
9 await ProcessJobAsync(schedules);
10 await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken);
11 }
12 }
于是原因便是,当时加了这个empty if block后,由于PreferenceService.GetSchedules总不是null,所以没有进入问题flow;后来配置变了,返回了null,进入问题flow,问题flow又错过了await Task.Delay(),所以悲剧发生。。
据这位朋友说,他的同事后来说:"这个empty if block当时是个placeholder。现在不用了,可以删了" ……。。唉,删是好删,不过在发现root cause之前可是让这位朋友背了不少时间的锅哈
总结
一次.net code中的placeholder导致的高cpu诊断的更多相关文章
- [Java] HashMap 导致的高 CPU 使用率
今天在生产环境遇到一个问题,Java 应用程序的 cpu 使用比例很高,导致整台机器的 cpu 使用率高达 90% ,正常情况下是 20% 左右. 把 Thread dump 导出来,利用 IBM T ...
- 解决 VS Code 中 golang.org 被墙导致的 Go 插件安装失败问题
微软官方开发的 Go for Visual Studio Code 插件为 Go 语言 提供了丰富的支持.在 VS Code 中首次打开 Go 工作区后,VS Code 会自动检测当前开发环境为 Go ...
- 在VS Code中对Python进行单元测试
在VS Code中对Python进行单元测试 Python扩展支持使用Python的内置unittest框架以及pytest和Nose进行单元测试.要使用pytest和Nose,必须将它们安装到当前的 ...
- 在 VS Code 中遇到的一些问题
1.在安装时未配置右键快捷菜单,想重新添加 最简单的就是重新安装一遍,在安装过程中选择好. 其次可以通过以下注册表脚本导入(保存为 .reg 文件),注意因为有中文字符,需要使用记事本保存为 ANSI ...
- 微软发布 Pylance:改善 VS Code 中的 Python 体验
原标题:微软发布 Pylance:改善 VS Code 中的 Python 体验 来源:开源中国 微软宣布推出一种新的 Python 语言服务器,名为 Pylance,其可利用语言服务器协议与 VS ...
- Visual Studio Code中文文档(一)-快速入门
Visual Studio Code是一个轻量级但是十分强大的源代码编辑器,重要的是它在Windows, OS X 和Linux操作系统的桌面上均可运行.Visual Studio Code内置了对J ...
- 在 Visual Studio Code 中使用 PoweShell - CodeShell
一直希望在 Visual Studio Code 中使用 PowerShell,插件 CodeShell 提供了对于 PowerShell 的支持. 安装 首先按 F1,打开命令窗口,输入安装插件的命 ...
- [转]DllMain中不当操作导致死锁问题的分析——DllMain中要谨慎写代码(完结篇)
在CSDN中发现这篇文章,讲解的比较详细,所以在这里备份一个.原文链接:http://blog.csdn.net/breaksoftware/article/details/8167641 DllMa ...
- .Net中的Placeholder控件
NET中的placeholder控件用来做什么的?其实PLACEHOLDER控件,是用来做动态加载用户自定义控件时,一个占位置作用的控件,比如 在从一个Web页面转换到另一个Web页面时,你的ASP. ...
- 在vs code中使用ftp-sync插件实现客户端与服务器端代码的同步
在vs code中使用ftp-sync插件实现客户端与服务器端代码的同步 下载安装 vscode-ftp-sync 插件. 安装方法1. Ctrl+Shift+P 输入 ext install [插件 ...
随机推荐
- 【BOOK】解析库--pyquery
CSS选择器 1.初始化 html=''' <div> <ul> <li class="item-0">first item</li> ...
- Mac下如何使用EVE-NG的telnet客户端和wireshark抓包
当我没有安装SecureCRT,点击启动的设备,弹出使用终端打开,但是由于eve中telnet使用的url是telnet xx.xx.xx.xx:xxxx 的形式,其在终端app中不能正常工作,tel ...
- python机器学习——PCA降维算法
背景与原理: PCA(主成分分析)是将一个数据的特征数量减少的同时尽可能保留最多信息的方法.所谓降维,就是在说对于一个$n$维数据集,其可以看做一个$n$维空间中的点集(或者向量集),而我们要把这个向 ...
- java中list对象不同属性去重合并
需求:将list中对象的不同属性对应的值去重后,赋值给另一个属性! 实现效果如下图:
- iOS设置textView的placeholder
转载:http://blog.sina.com.cn/s/blog_7a1b23430102wkys.html #import "ViewController.h" @interf ...
- MBR和gpt说明
1.MBR MBR的全称是Master Boot Record(主引导记录),MBR早在1983年IBM PC DOS 2.0中就已经提出.之所以叫"主引导记录",是因为它是存在于 ...
- AVD文件转移到非系统盘
AVD文件默认是生成在C:\Users\用户名\.android\avd目录下面的,而AVD文件非常大,可以用下面的方法将AVD文件转移到其他盘中. 1. 将每个模拟器对应的***.avd文件夹的内容 ...
- 【摘】python和它的super
python和它的super 如果用过python2,你一定见过下面这个奇怪的代码 class Mama(object): def says(self): print('i am mama') cla ...
- vue多图片上传组件
<template> <!-- 上传控件 用法: <upload-widget v-model="imgUrl"></upload-widget ...
- renren-fast-vue人人开源前端项目搭建保姆级教程
1.从gitee上clone项目 git clone https://gitee.com/renrenio/renren-fast-vue.git 2.准备好python环境 需要有Python2以上 ...