重新整理 .net core 實踐篇 ———— linux上性能排查 [外篇]
- 2022 年 11 月 6 日
- 筆記
- .net core(web)
前言
該文的前置篇為:
//www.cnblogs.com/aoximin/p/16839830.html
本文介紹性能排查。
正文
上一節是出現錯誤了,如何去排查具體問題。
這一節介紹一下性能排查。
還是上文的例子作為演示://buggyambfiles.blob.core.windows.net/bin/buggyamb_v1.1.zip
項目地址://github.com/ahmetmithat/buggyamb
本文實驗的還是lldb 和 sos。
對比一下cpu 情況。
實驗實施條件:
請求前:
點擊請求後:
這樣對比還是很大的哈。
那麼我們來看下啥子情況吧。
查看進程名:
那麼當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 自帶的。
那麼怎麼知道他的位置呢?
這樣可以查找到位置。
可以看到10秒後記憶體升高了。
那麼就可以上一章的內容了,進入lldb。
lldb –core coredump.manual.1.108232
然後查看執行緒:
看這個執行緒,發現和其他GC mode 不一樣。
那麼就有一個東西需要科普了,分別是cooperative 和 preemptive。
如果執行緒的 GC 模式設置為 「搶佔」,則表示 GC 可以隨時掛起此執行緒。 相比之下,協作模式意味著 GC 必須等待執行緒切換到搶佔模式,然後才能掛起它。 當執行緒運行託管程式碼時,它處於協作模式。
這句話什麼意思呢? 就是說這個執行緒在佔用cpu的意思。那麼cpu 高就應該看這個東西了。
setthread 14 然後切到這個執行緒。 這裡就不解釋了,都是上一章的東西。
然後調用一下clrstack。
然後來看一下幹了什麼?
感覺是在做字元串拼接啊。
那麼這個時候是會造成cpu高和記憶體高的,那麼要證明自己的猜想。
使用dso 查看一下。
Displays all managed objects found within the bounds of the current stack.
看下這個string,為什麼看這個呢?因為這個string,和System.Data.DataRow 比較近,這個可以學習彙編可能跟容易理解。
查看了一下這個倒是有100m。
讀取一下記憶體,看下裡面是什麼?
那麼我們知道,第二次轉儲文件的時候記憶體是上述了的。
那麼同樣的操作在第二個裡面執行:
lldb --core /tmp/coredump.manual.2.108232
setthread 15
dso
這裡已經變成了string[]
用dumparray 00007f48e538a4b0 查看一下這個string[] 對象是啥?
看下第一個的string 對象的情況:
讀取一下記憶體:
memory read -c 384 00007f48c3bc8f68
這裡就基本確認問題了。
但是這樣去定位問題,其實是有點慢的。而且發現,這個定位在cpu 倒是一個不錯的選擇,但是定位記憶體顯得不那麼合理。
因為cpu不高的情況,但是記憶體高的情況,這個時候肯定就是有很多碎片沒有回收,上面查的情況是根據執行去判斷的。
統計的方法定位問題是比較快的。
兩個裡面查看統計:
dumpheap -stat
第一個:
第二個:
發現這個system.string 兩個都很大,且變多了,而DataRow 也不少。
但是這裡漲的又不成比例,比如這裡對象漲了幾百,但是記憶體漲了200m。
這個時候可能就懷疑 大型對象堆 (LOH) 的問題了。
那麼查一下大於85000位元組的數據統計。
dumpheap -stat -min 85000
第一個:
第二個:
運行 dumpheap -stat -min 85000 -live。 此命令僅顯示根於某處的對象。 在此示例中,只有正確的對象實例 string 位於 LOH 中。
-live 就是活躍的意思,也就是應用程式正在使用的,不會被GC的。
這裡有4個,看下這4個是啥吧。
然後查看一個的記憶體:
這樣就定位到了。
但是還得查看一下這個對象位置在哪? 怎麼辦呢?用SOS的命令:gcroot
這個是源程式碼內部的,看的不清楚。
使用-all
這樣就直接定位到行了。
原因就是string+=string,等於String.Concat(System.String[]) 造成大量string 對象複製堆積。
結
下一節介紹procDump 和 dotnet-dump,procDump 這個挺好用的,dotnet-dump 更為方便。基本是必學的。