前言
该文的前置篇为:
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上性能排查 [外篇]](https://m.360buyimg.com/jdcms/jfs/t1/204127/33/27705/43711/63672b9cE89286a9c/4c1649d6dfcfab80.png)
请求前:
![重新整理 .net core 实践篇 ———— linux上性能排查 [外篇] 重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]](https://m.360buyimg.com/jdcms/jfs/t1/114369/16/30639/64679/63672b9cE8a5495ab/f361e693f71ca22e.png)
点击请求后:
![重新整理 .net core 实践篇 ———— linux上性能排查 [外篇] 重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]](https://m.360buyimg.com/jdcms/jfs/t1/99205/31/32789/16958/63672b9dE95c363fd/ce414faa54489a71.png)
这样对比还是很大的哈。
那么我们来看下啥子情况吧。
查看进程名:
![重新整理 .net core 实践篇 ———— linux上性能排查 [外篇] 重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]](https://m.360buyimg.com/jdcms/jfs/t1/185035/35/30499/8318/63672b9dE096e01f0/3342d3c6ebb0a64c.png)
那么当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上性能排查 [外篇]](https://m.360buyimg.com/jdcms/jfs/t1/48468/19/26513/5600/63672b9fE9fef4d0e/91da99e4e68b415a.png)
这样可以查找到位置。
![重新整理 .net core 实践篇 ———— linux上性能排查 [外篇] 重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]](https://m.360buyimg.com/jdcms/jfs/t1/175210/30/29080/3346/63672b9fEdff19e2c/b2b4d5eb729e9d0c.png)
可以看到10秒后内存升高了。
那么就可以上一章的内容了,进入lldb。
lldb --core coredump.manual.1.108232
然后查看线程:
![重新整理 .net core 实践篇 ———— linux上性能排查 [外篇] 重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]](https://m.360buyimg.com/jdcms/jfs/t1/60347/11/22511/41402/63672b9fE6c8eff40/62bf020643f9f931.png)
看这个线程,发现和其他GC mode 不一样。
那么就有一个东西需要科普了,分别是cooperative 和 preemptive。
如果线程的 GC 模式设置为 “抢占”,则表示 GC 可以随时挂起此线程。 相比之下,协作模式意味着 GC 必须等待线程切换到抢占模式,然后才能挂起它。 当线程运行托管代码时,它处于协作模式。
这句话什么意思呢? 就是说这个线程在占用cpu的意思。那么cpu 高就应该看这个东西了。
setthread 14 然后切到这个线程。 这里就不解释了,都是上一章的东西。
然后调用一下clrstack。
![重新整理 .net core 实践篇 ———— linux上性能排查 [外篇] 重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]](https://m.360buyimg.com/jdcms/jfs/t1/123506/33/31323/80627/63672ba0Eb503cf5f/8c99a935700e7792.png)
然后来看一下干了什么?
![重新整理 .net core 实践篇 ———— linux上性能排查 [外篇] 重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]](https://m.360buyimg.com/jdcms/jfs/t1/224020/33/16532/13198/63672ba0Ebe03a5ad/4ced74ebcb1018cb.png)
感觉是在做字符串拼接啊。
那么这个时候是会造成cpu高和内存高的,那么要证明自己的猜想。
使用dso 查看一下。
Displays all managed objects found within the bounds of the current stack.
![重新整理 .net core 实践篇 ———— linux上性能排查 [外篇] 重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]](https://m.360buyimg.com/jdcms/jfs/t1/69787/14/23523/34643/63672ba1Ebbe992ac/e4c3d10109089165.png)
看下这个string,为什么看这个呢?因为这个string,和System.Data.DataRow 比较近,这个可以学习汇编可能跟容易理解。
![重新整理 .net core 实践篇 ———— linux上性能排查 [外篇] 重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]](https://m.360buyimg.com/jdcms/jfs/t1/132821/14/31249/19872/63672ba1E0bb68044/5c7ccca5ef5b1435.png)
查看了一下这个倒是有100m。
读取一下内存,看下里面是什么?
![重新整理 .net core 实践篇 ———— linux上性能排查 [外篇] 重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]](https://m.360buyimg.com/jdcms/jfs/t1/140053/34/30967/45221/63672ba2E764605ab/8e88bbe6edbf1194.png)
那么我们知道,第二次转储文件的时候内存是上述了的。
那么同样的操作在第二个里面执行:
lldb --core /tmp/coredump.manual.2.108232
setthread 15
dso
![重新整理 .net core 实践篇 ———— linux上性能排查 [外篇] 重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]](https://m.360buyimg.com/jdcms/jfs/t1/201655/4/26398/37941/63672ba2E5491c5ed/ce7b0c920421d49b.png)
这里已经变成了string[]
用dumparray 00007f48e538a4b0 查看一下这个string[] 对象是啥?
![重新整理 .net core 实践篇 ———— linux上性能排查 [外篇] 重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]](https://m.360buyimg.com/jdcms/jfs/t1/138844/30/31077/13287/63672ba2E1aa30603/5f48f0a36736cee4.png)
看下第一个的string 对象的情况:
![重新整理 .net core 实践篇 ———— linux上性能排查 [外篇] 重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]](https://m.360buyimg.com/jdcms/jfs/t1/173494/26/31601/20704/63672ba2E275a1c27/50b6ecaf151e06b1.png)
读取一下内存:
memory read -c 384 00007f48c3bc8f68
![重新整理 .net core 实践篇 ———— linux上性能排查 [外篇] 重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]](https://m.360buyimg.com/jdcms/jfs/t1/198899/31/29033/45179/63672ba3Ee6997808/221334091448f0e5.png)
这里就基本确认问题了。
但是这样去定位问题,其实是有点慢的。而且发现,这个定位在cpu 倒是一个不错的选择,但是定位内存显得不那么合理。
因为cpu不高的情况,但是内存高的情况,这个时候肯定就是有很多碎片没有回收,上面查的情况是根据执行去判断的。
统计的方法定位问题是比较快的。
两个里面查看统计:
dumpheap -stat
第一个:
![重新整理 .net core 实践篇 ———— linux上性能排查 [外篇] 重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]](http://bbsmax.ikafan.com/static/L3Byb3h5L2h0dHBzL2ltZzIwMjIuY25ibG9ncy5jb20vYmxvZy8xMjg5Nzk0LzIwMjIxMS8xMjg5Nzk0LTIwMjIxMTA2MDAxNTU0NTgyLTg2ODkyODE1MS5wbmc=.jpg)
第二个:
![重新整理 .net core 实践篇 ———— linux上性能排查 [外篇] 重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]](http://bbsmax.ikafan.com/static/L3Byb3h5L2h0dHBzL2ltZzIwMjIuY25ibG9ncy5jb20vYmxvZy8xMjg5Nzk0LzIwMjIxMS8xMjg5Nzk0LTIwMjIxMTA2MDAxNjExMDg5LTEyNjI4NTg2MzkucG5n.jpg)
发现这个system.string 两个都很大,且变多了,而DataRow 也不少。
但是这里涨的又不成比例,比如这里对象涨了几百,但是内存涨了200m。
这个时候可能就怀疑 大型对象堆 (LOH) 的问题了。
那么查一下大于85000字节的数据统计。
dumpheap -stat -min 85000
第一个:
![重新整理 .net core 实践篇 ———— linux上性能排查 [外篇] 重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]](https://m.360buyimg.com/jdcms/jfs/t1/146181/5/32040/6826/63672ba3E3072317a/c8fb4e18f51eca03.png)
第二个:
![重新整理 .net core 实践篇 ———— linux上性能排查 [外篇] 重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]](https://m.360buyimg.com/jdcms/jfs/t1/192196/35/30330/7886/63672ba3E289f9582/4bc566394deb3459.png)
运行 dumpheap -stat -min 85000 -live。 此命令仅显示根于某处的对象。 在此示例中,只有正确的对象实例 string 位于 LOH 中。
-live 就是活跃的意思,也就是应用程序正在使用的,不会被GC的。
![重新整理 .net core 实践篇 ———— linux上性能排查 [外篇] 重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]](https://m.360buyimg.com/jdcms/jfs/t1/188025/1/30130/5826/63672ba4E49b7c183/8df18e95e93a3888.png)
这里有4个,看下这4个是啥吧。
![重新整理 .net core 实践篇 ———— linux上性能排查 [外篇] 重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]](https://m.360buyimg.com/jdcms/jfs/t1/214697/40/22922/9719/63672ba5E1ef9aefe/e9c6e66a4fe33623.png)
然后查看一个的内存:
![重新整理 .net core 实践篇 ———— linux上性能排查 [外篇] 重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]](https://m.360buyimg.com/jdcms/jfs/t1/217300/28/22539/30087/63672ba7Eac3c6ea6/8b7bae948cc36f3a.png)
这样就定位到了。
但是还得查看一下这个对象位置在哪? 怎么办呢?用SOS的命令:gcroot
![重新整理 .net core 实践篇 ———— linux上性能排查 [外篇] 重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]](https://m.360buyimg.com/jdcms/jfs/t1/223920/39/17342/20361/63672ba8Eb031a754/d9656f20f27628f0.png)
这个是源代码内部的,看的不清楚。
使用-all
![重新整理 .net core 实践篇 ———— linux上性能排查 [外篇] 重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]](https://m.360buyimg.com/jdcms/jfs/t1/127252/17/32409/29869/63672ba8E804ee2a6/9903909a47de0024.png)
这样就直接定位到行了。
原因就是string+=string,等于String.Concat(System.String[]) 造成大量string 对象复制堆积。
结
下一节介绍procDump 和 dotnet-dump,procDump 这个挺好用的,dotnet-dump 更为方便。基本是必学的。
标签:

留言评论