重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]

时间:2022-11-06 11:05:11

前言

该文的前置篇为:

https://www.cnblogs.com/aoximin/p/16839830.html

本文介绍性能排查。

正文

上一节是出现错误了,如何去排查具体问题。

这一节介绍一下性能排查。

还是上文的例子作为演示:https://buggyambfiles.blob.core.windows.net/bin/buggyamb_v1.1.zip

项目地址:https://github.com/ahmetmithat/buggyamb

本文实验的还是lldb 和 sos。

对比一下cpu 情况。

实验实施条件:

重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]

请求前:

重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]

点击请求后:

重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]

这样对比还是很大的哈。

那么我们来看下啥子情况吧。

查看进程名:

重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]

那么当cpu 高的时候进行抓取,一般抓取两个,两个间隔10秒左右。

为什么抓取两个呢? 因为好对比作用,更好定位,这个多实验实验就清楚了。

抓取命令:

/usr/share/dotnet/shared/Microsoft.NETCore.App/3.1.30/createdump 108232 -f /tmp/coredump.manual.1.%d
/usr/share/dotnet/shared/Microsoft.NETCore.App/3.1.30/createdump 108232 -f /tmp/coredump.manual.2.%d

两个命令间隔10秒。

我们知道这个createdump 是 dotcore runtime 自带的。

那么怎么知道他的位置呢?

重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]

这样可以查找到位置。

重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]

可以看到10秒后内存升高了。

那么就可以上一章的内容了,进入lldb。

lldb --core coredump.manual.1.108232

然后查看线程:

重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]

看这个线程,发现和其他GC mode 不一样。

那么就有一个东西需要科普了,分别是cooperative 和 preemptive。

如果线程的 GC 模式设置为 “抢占”,则表示 GC 可以随时挂起此线程。 相比之下,协作模式意味着 GC 必须等待线程切换到抢占模式,然后才能挂起它。 当线程运行托管代码时,它处于协作模式。

这句话什么意思呢? 就是说这个线程在占用cpu的意思。那么cpu 高就应该看这个东西了。

setthread 14 然后切到这个线程。 这里就不解释了,都是上一章的东西。

然后调用一下clrstack。

重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]

然后来看一下干了什么?

重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]

感觉是在做字符串拼接啊。

那么这个时候是会造成cpu高和内存高的,那么要证明自己的猜想。

使用dso 查看一下。

Displays all managed objects found within the bounds of the current stack.

重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]

看下这个string,为什么看这个呢?因为这个string,和System.Data.DataRow 比较近,这个可以学习汇编可能跟容易理解。

重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]

查看了一下这个倒是有100m。

读取一下内存,看下里面是什么?

重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]

那么我们知道,第二次转储文件的时候内存是上述了的。

那么同样的操作在第二个里面执行:

lldb --core /tmp/coredump.manual.2.108232
setthread 15
dso

重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]

这里已经变成了string[]

用dumparray 00007f48e538a4b0 查看一下这个string[] 对象是啥?

重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]

看下第一个的string 对象的情况:

重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]

读取一下内存:

memory read -c 384 00007f48c3bc8f68

重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]

这里就基本确认问题了。

但是这样去定位问题,其实是有点慢的。而且发现,这个定位在cpu 倒是一个不错的选择,但是定位内存显得不那么合理。

因为cpu不高的情况,但是内存高的情况,这个时候肯定就是有很多碎片没有回收,上面查的情况是根据执行去判断的。

统计的方法定位问题是比较快的。

两个里面查看统计:

dumpheap -stat

第一个:

重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]

第二个:

重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]

发现这个system.string 两个都很大,且变多了,而DataRow 也不少。

但是这里涨的又不成比例,比如这里对象涨了几百,但是内存涨了200m。

这个时候可能就怀疑 大型对象堆 (LOH) 的问题了。

那么查一下大于85000字节的数据统计。

dumpheap -stat -min 85000

第一个:

重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]

第二个:

重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]

运行 dumpheap -stat -min 85000 -live。 此命令仅显示根于某处的对象。 在此示例中,只有正确的对象实例 string 位于 LOH 中。

-live 就是活跃的意思,也就是应用程序正在使用的,不会被GC的。

重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]

这里有4个,看下这4个是啥吧。

重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]

然后查看一个的内存:

重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]

这样就定位到了。

但是还得查看一下这个对象位置在哪? 怎么办呢?用SOS的命令:gcroot

重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]

这个是源代码内部的,看的不清楚。

使用-all

重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]

这样就直接定位到行了。

原因就是string+=string,等于String.Concat(System.String[]) 造成大量string 对象复制堆积。

下一节介绍procDump 和 dotnet-dump,procDump 这个挺好用的,dotnet-dump 更为方便。基本是必学的。