公司的产品一直紧跟 .net core 3.0 preview 不断升级, 部署到 Linux 服务器后, 偶尔会出现某个进程CPU占用100%.
  由于服务部署在云上, 不能使用远程调试; 在局域网内的Linux 服务器 或 Windows开发机上又不能重现这个问题, 联想到Java的jstack, 很是羡慕啊. 想到.net core 已经出来这么久了, 还是试着找找看吧, 结果还真找到一篇博客Introducing diagnostics improvements in .NET Core 3.0

  这篇文章介绍了3个工具

  • dotnet-counters: 实时统计runtime的状况, 包括 CPU、内存、GC、异常等
  • dotnet-trace: 类似性能探测器
  • dotnet-dump: 程序崩溃时使用该工具

  这次使用的是dotnet-dump, 即使程序没有崩溃, 也可以dump程序快照, 用于分析

实验环境

ubuntu-16.04.5-desktop-amd64
SDK 3.0.100-preview6-012264

1. 新建一个简单Console程序(只能是 .net core 3.0的程序, 不支持 .net core 2.2), 模拟CPU占用100%的情况

mkdir NetCoreDumpTest && cd NetCoreDumpTest
dotnet new console

编辑Program.cs

namespace NetCoreDumpTest
{
using System;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
Task.Factory.StartNew(() => PrintNumber("Print", ));
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
} static void PrintNumber(string message, int startNumber)
{
var number = startNumber;
while (true)
Console.WriteLine($"{message} {number++}");
}
}
}

2. 安装dotnet-dump

dotnet tool install --global dotnet-dump --version 1.0.-preview6.19311.1

提示

If you are using bash, you can add it to your profile by running the following command:

cat << \EOF >> ~/.bash_profile
# Add .NET Core SDK tools
export PATH="$PATH:/home/****/.dotnet/tools"
EOF You can add it to the current session by running the following command: export PATH="$PATH:/home/****/.dotnet/tools" You can invoke the tool using the following command: dotnet-dump
Tool 'dotnet-dump' (version '1.0.4-preview6.19311.1') was successfully installed.

建议将 $HOME/.dotnet/tools加入到PATH, 好吧, 照着做吧, 记得使用下面的命令使设置立即生效

source ~/.bash_profile

3. 使用 dotnet NetCoreDumpTest.dll 启动我们的问题程序, 然后使用  ps -ef | grep dotnet  查看程序的进程ID, 可以看到进程ID是 3411

ps -ef | grep dotnet
z*****e : pts/ :: dotnet NetCoreDumpTest.dll
z*****e : pts/ :: grep --color=auto dotnet

针对进程3411, 我们还需要知道是哪个线程占CPU, 使用 top -Hp 3411 可以列出所有线程, 由于top每隔3秒刷新一次, 所以可能需要多观察几秒才能看到具体是哪个线程占用CPU比较高, 这里我们可以看到是PID=3418的线程(Linux的进程ID和线程ID请自行了解一下).

top -Hp
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
z*****e R 10.3 1.4 :20.68 dotnet
z*****e S 0.0 1.4 :00.11 dotnet
z*****e S 0.0 1.4 :00.02 dotnet
z*****e S 0.0 1.4 :00.00 dotnet
z*****e S 0.0 1.4 :00.00 dotnet
z*****e S 0.0 1.4 :00.01 dotnet
z*****e S 0.0 1.4 :00.00 dotnet
z*****e S 0.0 1.4 :00.00 dotnet
z*****e S 0.0 1.4 :00.00 dotnet

获取dump, 只能正对进程进行dump, 所以我们输入的是 3411

dotnet-dump collect -p
Writing minidump with heap to /tmp/core_20190623_075649
Complete

4. 分析

dotnet-dump analyze core_20190623_075649

使用clrthreads 查看所有线程

>clrthreads
ThreadCount:
UnstartedThread:
BackgroundThread:
PendingThread:
DeadThread:
Hosted Runtime: no
Lock
DBG ID OSID ThreadOBJ State GC Mode GC Alloc Context Domain Count Apt Exception
d53 0000000001307D80 Preemptive : Ukn
d57 000000000135BBD0 Preemptive : Ukn (Finalizer)
d59 00007F666C0009F0 Preemptive : Ukn (Threadpool Worker)
d5a 000000000130DA40 Preemptive 00007F6678106860:00007F6678106F20 Ukn (Threadpool Worker)

我们关心的线程3418的16进制是d5a, 也就是最后一行, 它的DBG是7, 我们需要使用 setthread 7, 将其设置为  当前操作的线程

然后使用 clrstack 获取线程调用信息

> setthread
> clrstack
OS Thread Id: 0xd5a ()
Child SP IP Call Site
00007F6715561558 00007f671a2bd4bd [InlinedCallFrame: 00007f6715561558] Interop+Sys.Write(System.Runtime.InteropServices.SafeHandle, Byte*, Int32)
00007F6715561558 00007f669f669a9e [InlinedCallFrame: 00007f6715561558] Interop+Sys.Write(System.Runtime.InteropServices.SafeHandle, Byte*, Int32)
00007F6715561540 00007F669F669A9E ILStubClass.IL_STUB_PInvoke
00007F67155615E0 00007F669F67333E System.ConsolePal.Write(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte*, Int32, Boolean)
00007F67155616A0 00007F669F67360C System.ConsolePal.Write(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte[], Int32, Int32, Boolean) [/_/src/System.Console/src/System/ConsolePal.Unix.cs @ ]
00007F67155616C0 00007F669F672B2A System.IO.StreamWriter.Flush(Boolean, Boolean) [/_/src/System.Private.CoreLib/shared/System/IO/StreamWriter.cs @ ]
00007F6715561710 00007F669F6729F3 System.IO.StreamWriter.WriteLine(System.String) [/_/src/System.Private.CoreLib/shared/System/IO/StreamWriter.cs @ ]
00007F6715561760 00007F669F6727D3 System.IO.TextWriter+SyncTextWriter.WriteLine(System.String) [/_/src/System.Private.CoreLib/shared/System/IO/TextWriter.cs @ ]
00007F67155617A0 00007F669F672770 System.Console.WriteLine(System.String) [/_/src/System.Console/src/System/Console.cs @ ]
00007F67155617C0 00007F669F663791 NetCoreDumpTest.Program.PrintNumber(System.String, Int32) [/home/zhouke/NetCoreDumpTest/Program.cs @ ]
00007F6715561800 00007F669F6636D9 NetCoreDumpTest.Program+<>c.<Main>b__0_0()
00007F6715561820 00007F669F1872A1 System.Threading.Tasks.Task.InnerInvoke() [/_/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs @ ]
00007F6715561840 00007F669F18CBC2 System.Threading.Tasks.Task+<>c.<.cctor>b__274_0(System.Object) [/_/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs @ ]
00007F6715561850 00007F669F171AF2 System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(System.Threading.Thread, System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) [/_/src/System.Private.CoreLib/shared/System/Threading/ExecutionContext.cs @ ]
00007F6715561890 00007F669F187111 System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef, System.Threading.Thread) [/_/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs @ ]
00007F6715561910 00007F669F186F28 System.Threading.Tasks.Task.ExecuteEntryUnsafe(System.Threading.Thread) [/_/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs @ ]
00007F6715561930 00007F669F186EBB System.Threading.Tasks.Task.ExecuteFromThreadPool(System.Threading.Thread)
00007F6715561940 00007F669F17B754 System.Threading.ThreadPoolWorkQueue.Dispatch() [/_/src/System.Private.CoreLib/shared/System/Threading/ThreadPool.cs @ ]
00007F67155619C0 00007F669F169A5B System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() [/_/src/System.Private.CoreLib/src/System/Threading/ThreadPool.CoreCLR.cs @ ]
00007F6715561D50 00007f6718a1ccaf [DebuggerU2MCatchHandlerFrame: 00007f6715561d50]

哗啦啦一大片, 有点Java调用堆栈的味道, 不过我们还是找到了我们的问题代码

NetCoreDumpTest.Program.PrintNumber(System.String, Int32)

有时候我们想知道传入的什么参数导致CPU占用高, 可以给clrstack加上参数 -a

> clrstack -a
..............
00007F0DD6FFC7C0 00007F0D6EEF3791 NetCoreDumpTest.Program.PrintNumber(System.String, Int32) [/home/zhouke/NetCoreDumpTest/Program.cs @ ]
PARAMETERS:
message (0x00007F0DD6FFC7E8) = 0x00007f0d4800b8b0
startNumber (0x00007F0DD6FFC7E4) = 0x0000000000000005
LOCALS:
0x00007F0DD6FFC7E0 = 0x000000000014e42b
0x00007F0DD6FFC7DC = 0x0000000000000001
...............

可以看到PARAMETERS里, startNumber作为值类型, 可以直接看到数值为5, 而message是引用类型, 指向0x00007f0d4800b8b0, 这时候需要用到 dumpobj 命令

> dumpobj 0x00007f0d4800b8b0
Name: System.String
MethodTable: 00007f0d6ef70f90
EEClass: 00007f0d6eede1c0
Size: (0x20) bytes
File: /home/zhouke/dotnet/shared/Microsoft.NETCore.App/3.0.-preview6--/System.Private.CoreLib.dll
String: Print
Fields:
MT Field Offset Type VT Attr Value Name
00007f0d6ef6a138 400022b System.Int32 instance _stringLength
00007f0d6ef66f38 400022c c System.Char instance _firstChar
00007f0d6ef70f90 400022d System.String static 00007f0d47fff360 Empty

好了, 可以看到它是一个字符串, 内容为 "Print"

假如message是一个复杂类型, 可以查看Fields下面的信息进一步查看

clrstack 还有一个实验性质的参数 -i, 协助查看各种变量信息, 需要用到lldb, 按照官方教程, 我暂时没有实验成功.

查看进程ID和线程ID, 更方便的方法是 htop(需要安装), 然后按 F4 进行过滤, 输入dotnet 即可

这张图是重新运行问题程序的结果, 进程ID和线程ID与前面不一样

第二行白色的是进程ID=1650, 第一行CPU占用高, 是问题线程ID=1658

End

使用dotnet-dump 查找 .net core 3.0 占用CPU 100%的原因的更多相关文章

  1. linux下查找java进程占用CPU过高原因

    1. 查找进程 top查看进程占用资源情况 明显看出java的两个进程22714,12406占用过高cpu.   2.查找线程 使用top -H -p <pid>查看线程占用情况   3. ...

  2. ASP.NET Core 1.0 基础与应用启动

    .NET Core http://dotnet.github.io/[https://github.com/dotnet/coreclr] ASP.NET Core 1.0 https://get.a ...

  3. Professional C# 6 and .NET Core 1.0 - Creating Hello, World! with Visual Studio

    本文为转载,学习研究 Creating Hello, World! with Visual Studio Chapter 1, “.NET Application Architectures,” ex ...

  4. DotNet Core 1.0 集成 CentOS 开发与运行环境部署

    一.     DotNet Core 1.0 开发环境部署 操作系统安装 我们使用CentOS 7.2.1511版本. 安装libunwind库 执行:sudo yum install libunwi ...

  5. 北京时间28号0点以后Scott Hanselman同志台宣布dotnet core 1.0 rtm

    今日占住微信号头条的好消息<终于来了!微软.Net Core 1.0下载放出>.本人立马跑到官网http://dot.net看了一下,仍然是.net core 1.0 Preview 1版 ...

  6. centos 7 && dotnet core 2.0 && nginx && supervisor

    前提 系统:centos 7 目录:/home/wwwroot/www.wuball.com dotnet core 2.0 官方指引 sudo rpm --import https://packag ...

  7. dotnet core 3.0 linux 部署小贴士

    dotnet core 3.0 目前还是测试版,在linux下安装 sdk 需要有一些注意事项 1.下载url https://dotnet.microsoft.com/download/thank- ...

  8. DotNet Core 2.0使用MySql实现Code First

    本教程使用vs2017 + dotnet core2.0 + MySql5.7.19 1.打开vs2017,文件>新建>项目,选择Asp.Net Core Web应用程序. 2.项目名称可 ...

  9. 卸载.net 5.0后使用dotnet提示Found .NET Core SDK

    之前安装了预览版本的vs2019后试了下,然后卸载了.但发现控制台执行dotnet相关命令提示Found .NET Core SDK, but did not find dotnet.dll at [ ...

随机推荐

  1. 我的省选 Day -11

    Day -11 上了一天的文化课,晚上才来到机房(神秘的一天.. 班里前一半的JuLao们都去参加省质检的同步赛了, 然而我太菜,早就跌到班级的中下下了(所以没得参加.. 所以今天上课时特别尴尬,班级 ...

  2. AtCoder Beginner Contest 115 题解

    题目链接:https://abc115.contest.atcoder.jp/ A Christmas Eve Eve Eve 题目: Time limit : 2sec / Memory limit ...

  3. POJ1016 Numbers That Count

    题目来源:http://poj.org/problem?id=1016 题目大意: 对一个非负整数定义一种运算(inventory):数这个数中各个数字出现的次数,然后按顺序记录下来.比如“55531 ...

  4. Codeforces 1161B(判断旋转对称)

    要点 外层暴力枚举转的"角度",会发现肯定是n的约数 对于m条线段想判定当前的"角度"是否ok,每个线段只要管它自己的下一个即可,不必画个圈遍历一遍 之后将本来 ...

  5. P1984 [SDOI2008]烧水问题(具体证明)

    传送门 我见过的第二恶心的题,第一是糖果传递... 以下是一堆具体的证明,自己想的,可能考虑不周,不想看也可以直接看结论 首先有一个很显然的贪心,烧开的水要尽量把热量传递出去 所以有一个比较显然的方法 ...

  6. shell命令学习

    shell快速入门 http://www.jb51.net/article/28514.htm 1.http://www.cnblogs.com/zhutoujin/articles/4678743. ...

  7. notepad++的tab设置为4个空格

    设置--首选项--语言--制表符设置--(勾选上)替换为空格

  8. (转)用户管理 之 Linux 用户(user)和用户组(group)管理概述

    用户管理 之 Linux 用户(user)和用户组(group)管理概述  原文:http://www.cnblogs.com/licheng/p/6103992.html 一.理解Linux的单用户 ...

  9. (转)linux paste命令用法详解

    linux paste命令用法详解原文:http://www.xfcodes.com/linuxcmd/mulu/10211.htmlinux下paste命令,可用于合并文件的列. 功能说明:合并文件 ...

  10. (转)linux route命令详解

    linux route命令详解 原文:https://www.cnblogs.com/lpfuture/p/5857738.html   &&   http://blog.csdn.n ...