偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

騰訊C++一面:如何排查CPU占用率過(guò)高問(wèn)題?

開(kāi)發(fā) 前端
當(dāng)遇到 CPU 占用率過(guò)高問(wèn)題時(shí),我們需要迅速排查,找出根源并解決。在騰訊 C++ 一面這樣的技術(shù)面試中,考查如何排查該問(wèn)題,意在檢驗(yàn)候選人對(duì)系統(tǒng)底層運(yùn)行機(jī)制的掌握程度、性能調(diào)優(yōu)的實(shí)踐能力以及解決復(fù)雜問(wèn)題的思路。

在程序運(yùn)行過(guò)程中,CPU 占用率過(guò)高是一個(gè)不容忽視的問(wèn)題,它就像程序性能的 “絆腳石”,可能引發(fā)程序響應(yīng)遲緩、系統(tǒng)卡頓甚至崩潰等嚴(yán)重后果。比如,在一個(gè)高并發(fā)的在線交易系統(tǒng)里,若 CPU 占用率持續(xù)居高不下,用戶進(jìn)行交易操作時(shí),頁(yè)面加載時(shí)間會(huì)大幅延長(zhǎng),甚至出現(xiàn)交易失敗的情況,極大地影響用戶體驗(yàn)與業(yè)務(wù)開(kāi)展。

當(dāng)遇到 CPU 占用率過(guò)高問(wèn)題時(shí),我們需要迅速排查,找出根源并解決。在騰訊 C++ 一面這樣的技術(shù)面試中,考查如何排查該問(wèn)題,意在檢驗(yàn)候選人對(duì)系統(tǒng)底層運(yùn)行機(jī)制的掌握程度、性能調(diào)優(yōu)的實(shí)踐能力以及解決復(fù)雜問(wèn)題的思路。接下來(lái),我們將從系統(tǒng)工具運(yùn)用、代碼邏輯審查、硬件狀態(tài)檢測(cè)等多個(gè)關(guān)鍵維度,全面且深入地剖析排查 CPU 占用率過(guò)高問(wèn)題的有效方法,助力開(kāi)發(fā)者在實(shí)際工作和面試中,都能游刃有余地應(yīng)對(duì)這一挑戰(zhàn)。接下來(lái),我就把自己在面試后深入研究的一些排查思路和方法分享給大家,希望能對(duì)遇到同樣問(wèn)題的小伙伴們有所幫助。

Part1.CPU占用率到底是什么?

1.1 CPU占用率

CPU 占用率,簡(jiǎn)單來(lái)說(shuō),就是指 CPU 在一段時(shí)間內(nèi)被使用的時(shí)間與總時(shí)間的比值,以百分比表示 。它直觀地反映了 CPU 的忙碌程度。打個(gè)比方,CPU 就像是工廠里的工人,CPU 占用率就是工人工作時(shí)間占總時(shí)間的比例。如果這個(gè)比例很高,就說(shuō)明工人一直處于忙碌狀態(tài),沒(méi)有多少空閑時(shí)間。

正常情況下,CPU 占用率會(huì)根據(jù)系統(tǒng)的負(fù)載情況在一定范圍內(nèi)波動(dòng)。一般來(lái)說(shuō),在系統(tǒng)空閑時(shí),CPU 占用率應(yīng)該很低,通常在 5% - 10% 左右 。當(dāng)我們進(jìn)行一些簡(jiǎn)單的操作,如瀏覽網(wǎng)頁(yè)、編輯文檔時(shí),CPU 占用率可能會(huì)上升到 10% - 30% 。而在運(yùn)行大型軟件、進(jìn)行復(fù)雜計(jì)算或者多任務(wù)處理時(shí),CPU 占用率可能會(huì)進(jìn)一步升高,達(dá)到 30% - 70% ,甚至在某些極端情況下接近 100% 。但如果 CPU 占用率長(zhǎng)期居高不下,超過(guò) 80% 甚至接近 100% ,就說(shuō)明系統(tǒng)可能出現(xiàn)了問(wèn)題,需要我們?nèi)ヅ挪楹徒鉀Q。

1.2 CPU使用率

用戶態(tài) CPU 使用率(user):表示 CPU 在用戶態(tài)運(yùn)行的時(shí)間百分比。用戶態(tài)是應(yīng)用程序運(yùn)行的模式,當(dāng)我們運(yùn)行一個(gè) C++ 程序時(shí),程序中的大部分代碼都是在用戶態(tài)執(zhí)行的。如果用戶態(tài) CPU 使用率過(guò)高,通常說(shuō)明應(yīng)用程序比較繁忙,可能存在一些復(fù)雜的計(jì)算邏輯或者頻繁的函數(shù)調(diào)用。比如,一個(gè)進(jìn)行大量數(shù)據(jù)加密和解密的程序,就會(huì)在用戶態(tài)占用較多的 CPU 時(shí)間。

內(nèi)核態(tài) CPU 使用率(system):表示 CPU 在內(nèi)核態(tài)運(yùn)行的時(shí)間百分比(不包括中斷)。內(nèi)核態(tài)是操作系統(tǒng)內(nèi)核運(yùn)行的模式,負(fù)責(zé)管理系統(tǒng)資源、進(jìn)程調(diào)度、設(shè)備驅(qū)動(dòng)等重要任務(wù)。當(dāng)應(yīng)用程序需要進(jìn)行系統(tǒng)調(diào)用,如讀寫文件、創(chuàng)建進(jìn)程等操作時(shí),就會(huì)從用戶態(tài)切換到內(nèi)核態(tài)。如果內(nèi)核態(tài) CPU 使用率高,說(shuō)明內(nèi)核比較繁忙,可能是由于系統(tǒng)調(diào)用過(guò)于頻繁,或者內(nèi)核中的某些驅(qū)動(dòng)程序存在問(wèn)題。

等待 I/O 的 CPU 使用率(iowait):也稱為 I/O 等待時(shí)間,它表示等待 I/O 操作完成的時(shí)間百分比。當(dāng)程序進(jìn)行磁盤讀寫、網(wǎng)絡(luò)通信等 I/O 操作時(shí),如果 I/O 設(shè)備的速度較慢,CPU 就需要等待 I/O 操作完成,這段時(shí)間就會(huì)被計(jì)入 iowait。iowait 高,說(shuō)明系統(tǒng)與硬件設(shè)備的 I/O 交互時(shí)間比較長(zhǎng),可能是磁盤性能不佳、網(wǎng)絡(luò)帶寬不足或者 I/O 設(shè)備故障等原因?qū)е碌?。例如,?dāng)程序頻繁讀取一個(gè)磁盤上的大文件時(shí),如果磁盤的讀寫速度較慢,就會(huì)導(dǎo)致 iowait 升高 。

軟中斷和硬中斷的 CPU 使用率:軟中斷是由軟件觸發(fā)的中斷,用于處理一些異步事件,如網(wǎng)絡(luò)數(shù)據(jù)包的接收、定時(shí)器到期等。硬中斷則是由硬件設(shè)備觸發(fā)的中斷,如鍵盤輸入、磁盤讀寫完成等。它們的使用率高,表明系統(tǒng)發(fā)生了大量的中斷。比如,在網(wǎng)絡(luò)通信中,如果網(wǎng)絡(luò)流量較大,就會(huì)產(chǎn)生大量的網(wǎng)絡(luò)中斷,導(dǎo)致軟中斷 CPU 使用率升高 。

1.3 系統(tǒng)資源相關(guān)知識(shí)

除了了解 CPU 使用率的相關(guān)概念,我們還需要對(duì)內(nèi)存、磁盤 I/O、網(wǎng)絡(luò)等系統(tǒng)資源與 CPU 占用率的關(guān)系有一定的認(rèn)識(shí) 。

內(nèi)存與 CPU的關(guān)系十分緊密。當(dāng)程序運(yùn)行時(shí),需要將程序代碼和數(shù)據(jù)加載到內(nèi)存中,CPU從內(nèi)存中讀取指令和數(shù)據(jù)進(jìn)行處理。如果內(nèi)存不足,系統(tǒng)會(huì)使用虛擬內(nèi)存(磁盤空間)來(lái)代替物理內(nèi)存,這會(huì)導(dǎo)致數(shù)據(jù)訪問(wèn)速度大幅下降,因?yàn)榇疟P的讀寫速度遠(yuǎn)遠(yuǎn)低于內(nèi)存。為了獲取數(shù)據(jù),CPU需要等待較長(zhǎng)時(shí)間,造成CPU利用率不足。此外,內(nèi)存泄漏也是一個(gè)常見(jiàn)的問(wèn)題,它會(huì)導(dǎo)致程序占用的內(nèi)存不斷增加,最終可能耗盡系統(tǒng)內(nèi)存,迫使系統(tǒng)頻繁進(jìn)行內(nèi)存回收和交換,從而影響CPU性能 。

磁盤 I/O 與 CPU 占用率也密切相關(guān)。頻繁的磁盤讀寫操作會(huì)導(dǎo)致 I/O 等待時(shí)間增加,從而使 iowait 升高,進(jìn)而影響 CPU 的利用率。如果磁盤的讀寫速度較慢,或者磁盤存在故障,就會(huì)導(dǎo)致程序在進(jìn)行磁盤 I/O 操作時(shí)花費(fèi)大量時(shí)間等待,使得 CPU 無(wú)法充分發(fā)揮其計(jì)算能力。例如,一個(gè)數(shù)據(jù)庫(kù)應(yīng)用程序,如果頻繁進(jìn)行磁盤讀寫操作來(lái)讀取和寫入數(shù)據(jù),而磁盤性能又較差,就會(huì)導(dǎo)致 iowait 升高,CPU 占用率也會(huì)相應(yīng)受到影響 。

網(wǎng)絡(luò)方面,網(wǎng)絡(luò)帶寬不足、網(wǎng)絡(luò)延遲過(guò)高或者網(wǎng)絡(luò)連接不穩(wěn)定,都會(huì)導(dǎo)致網(wǎng)絡(luò)通信效率低下。當(dāng)程序進(jìn)行網(wǎng)絡(luò)數(shù)據(jù)傳輸時(shí),就會(huì)出現(xiàn)等待網(wǎng)絡(luò)響應(yīng)的情況,這也會(huì)間接影響 CPU 的使用率。在一個(gè)網(wǎng)絡(luò)爬蟲(chóng)程序中,如果網(wǎng)絡(luò)帶寬有限,每次請(qǐng)求網(wǎng)頁(yè)時(shí)都需要等待較長(zhǎng)時(shí)間才能獲取數(shù)據(jù),那么在等待過(guò)程中,CPU 就處于空閑狀態(tài),造成資源浪費(fèi)。此外,大量的網(wǎng)絡(luò)數(shù)據(jù)包處理也會(huì)占用 CPU 資源,如果網(wǎng)絡(luò)流量過(guò)大,就可能導(dǎo)致 CPU 忙于處理網(wǎng)絡(luò)數(shù)據(jù)包,從而使其他任務(wù)的 CPU 占用率受到影響 。

Part2.認(rèn)識(shí)CPU性能指標(biāo)

在深入排查 CPU 性能問(wèn)題前,我們先來(lái)認(rèn)識(shí)幾個(gè)關(guān)鍵的 CPU 性能指標(biāo),它們?nèi)缤?CPU 的 “健康密碼”,能幫助我們準(zhǔn)確判斷 CPU 的工作狀態(tài) 。

2.1 平均負(fù)載(Load Average)

平均負(fù)載是指單位時(shí)間內(nèi),系統(tǒng)處于可運(yùn)行狀態(tài)和不可中斷狀態(tài)的平均進(jìn)程數(shù) ,也就是平均活躍進(jìn)程數(shù)。簡(jiǎn)單來(lái)說(shuō),它反映了系統(tǒng)的繁忙程度。可運(yùn)行狀態(tài)的進(jìn)程,是指正在使用 CPU 或者正在等待 CPU 的進(jìn)程;不可中斷狀態(tài)的進(jìn)程則是正處于內(nèi)核態(tài)關(guān)鍵流程中的進(jìn)程,并且這些流程是不可打斷的,最常見(jiàn)的是等待硬件設(shè)備的 I/O 響應(yīng)。

我們可以使用 uptime 命令或 top 命令來(lái)查看系統(tǒng)的平均負(fù)載。比如,執(zhí)行 uptime 命令后,得到的結(jié)果 “14:21:38 up 1 day, 1:22, 2 users, load average: 0.58, 0.65, 0.70”,其中最后三個(gè)數(shù)字 0.58、0.65、0.70 分別表示過(guò)去 1 分鐘、5 分鐘、15 分鐘的平均負(fù)載。

平均負(fù)載與 CPU 核心數(shù)密切相關(guān)。對(duì)于一個(gè)單核 CPU 系統(tǒng)來(lái)說(shuō),如果平均負(fù)載為 1,意味著 CPU 剛好被完全占用;如果平均負(fù)載大于 1,則表示有進(jìn)程在等待 CPU 資源,系統(tǒng)出現(xiàn)了過(guò)載。而在一個(gè) 4 核 CPU 系統(tǒng)中,當(dāng)平均負(fù)載為 4 時(shí),CPU 才被完全占用;若平均負(fù)載為 2,說(shuō)明 CPU 還有 50% 的空閑。一般認(rèn)為,當(dāng)平均負(fù)載高于 CPU 數(shù)量 70% 的時(shí)候,就需要關(guān)注并分析負(fù)載高的問(wèn)題了 。例如,在一個(gè)擁有 2 個(gè) CPU 核心的服務(wù)器上,如果 1 分鐘平均負(fù)載長(zhǎng)期高于 1.4,就可能會(huì)出現(xiàn)性能問(wèn)題,需要進(jìn)一步排查原因。

2.2 CPU 使用率

CPU 使用率,簡(jiǎn)單來(lái)說(shuō),就是在一段時(shí)間內(nèi),CPU 被占用的時(shí)間占總時(shí)間的比例,是一個(gè)百分比數(shù)值。它就像衡量 CPU 工作強(qiáng)度的 “體溫計(jì)”,直觀地反映了 CPU 在單位時(shí)間內(nèi)有多 “忙” 。

其計(jì)算方式并不復(fù)雜。對(duì)于單核 CPU 而言,在某一時(shí)間段內(nèi),若 CPU 執(zhí)行程序指令的時(shí)間為 t1,總時(shí)間為 T,那么該時(shí)間段內(nèi)的 CPU 使用率 = (t1 / T)× 100% 。例如,在 1 秒鐘內(nèi),CPU 有 0.5 秒在執(zhí)行程序指令,那么這 1 秒內(nèi)的 CPU 使用率就是 50%。而對(duì)于多核 CPU,計(jì)算方式則是將每個(gè)核心在單位時(shí)間內(nèi)的使用率相加,再除以核心數(shù)。假設(shè)一個(gè)四核 CPU,每個(gè)核心在 1 秒內(nèi)分別被占用 0.3 秒、0.4 秒、0.2 秒和 0.1 秒,那么總的 CPU 使用率就是(0.3 + 0.4 + 0.2 + 0.1)÷ 4 × 100% = 25% 。

當(dāng) CPU 使用率較高時(shí),如達(dá)到 80% - 90% 及以上,就意味著 CPU 正在承擔(dān)大量的計(jì)算任務(wù),計(jì)算機(jī)的響應(yīng)速度可能會(huì)變慢。以運(yùn)行大型 3D 游戲?yàn)槔?,游戲運(yùn)行時(shí),CPU 需要處理復(fù)雜的圖形算法、物理模擬以及大量的游戲邏輯,這使得 CPU 的使用率急劇上升。若此時(shí) CPU 性能不足,就會(huì)導(dǎo)致游戲畫面卡頓、幀率不穩(wěn)定等問(wèn)題。相反,當(dāng) CPU 使用率較低,如在待機(jī)或者只運(yùn)行一些簡(jiǎn)單的文本編輯軟件時(shí),CPU 使用率可能只有 10% - 20% 左右,計(jì)算機(jī)能夠快速響應(yīng)用戶的其他操作指令。

2.3 上下文切換

在多任務(wù)處理的環(huán)境中,Linux 系統(tǒng)看似能夠同時(shí)運(yùn)行多個(gè)任務(wù),但實(shí)際上,在同一時(shí)刻,CPU 只能執(zhí)行一個(gè)任務(wù)。為了實(shí)現(xiàn)多任務(wù)并發(fā)執(zhí)行的效果,操作系統(tǒng)引入了上下文切換機(jī)制,這就好比一場(chǎng)接力賽跑中的 “接力棒交接” 。

上下文切換,是指操作系統(tǒng)保存當(dāng)前正在執(zhí)行的任務(wù)(可以是進(jìn)程或線程)的狀態(tài)(即上下文),并加載另一個(gè)任務(wù)的狀態(tài),使得 CPU 能夠從一個(gè)任務(wù)快速切換到另一個(gè)任務(wù)執(zhí)行。這里的上下文,既包括虛擬內(nèi)存、棧、全局變量等用戶態(tài)的資源,也包括內(nèi)核堆棧、寄存器等內(nèi)核態(tài)的資源 。

在 Linux 系統(tǒng)中,進(jìn)程有多種狀態(tài),不同狀態(tài)與 CPU 的關(guān)系也各不相同:

  • 運(yùn)行態(tài)(Running):表示進(jìn)程正在被 CPU 執(zhí)行,或者在運(yùn)行隊(duì)列中等待被調(diào)度執(zhí)行。處于運(yùn)行態(tài)的進(jìn)程直接占用 CPU 資源,是 CPU 忙碌的直接原因。例如,當(dāng)我們啟動(dòng)一個(gè)計(jì)算密集型的程序時(shí),該程序的進(jìn)程會(huì)處于運(yùn)行態(tài),大量占用 CPU 時(shí)間進(jìn)行計(jì)算。
  • 可中斷睡眠態(tài)(Interruptible Sleep):進(jìn)程正在等待某一事件的發(fā)生,例如等待 I/O 操作完成、等待信號(hào)等。此時(shí)進(jìn)程處于睡眠狀態(tài),但可以通過(guò)信號(hào)喚醒。處于這種狀態(tài)的進(jìn)程不會(huì)占用 CPU 資源,直到被喚醒進(jìn)入就緒態(tài),才有可能被 CPU 調(diào)度執(zhí)行。比如,一個(gè)進(jìn)程發(fā)起了磁盤讀取操作,在等待磁盤返回?cái)?shù)據(jù)的過(guò)程中,它就處于可中斷睡眠態(tài)。
  • 不可中斷睡眠態(tài)(Uninterruptible Sleep):進(jìn)程等待某種無(wú)法通過(guò)信號(hào)喚醒的資源,通常是在等待硬件操作完成,如等待磁盤 I/O、等待網(wǎng)絡(luò)傳輸完成等。此時(shí)進(jìn)程不會(huì)響應(yīng)任何信號(hào),直到所等待的事件發(fā)生。不可中斷睡眠態(tài)的進(jìn)程雖然不占用 CPU 執(zhí)行時(shí)間,但會(huì)使系統(tǒng)的平均負(fù)載增加,因?yàn)樗幱诓豢芍袛嗟年P(guān)鍵流程中。例如,當(dāng)進(jìn)程向磁盤寫入大量數(shù)據(jù)時(shí),為了保證數(shù)據(jù)一致性,在寫入完成前,進(jìn)程會(huì)處于不可中斷睡眠態(tài)。
  • 暫停態(tài)(Stopped):進(jìn)程被暫停運(yùn)行,通常是接收到 SIGSTOP 信號(hào)導(dǎo)致。進(jìn)程停止運(yùn)行但沒(méi)有終止,所有的上下文信息都會(huì)被保留。暫停態(tài)的進(jìn)程不占用 CPU 資源,直到接收到 SIGCONT 信號(hào)恢復(fù)執(zhí)行并進(jìn)入就緒態(tài)。比如,我們?cè)谡{(diào)試程序時(shí),可以使用調(diào)試工具將進(jìn)程暫停在某個(gè)斷點(diǎn)處,此時(shí)進(jìn)程就處于暫停態(tài)。
  • 僵尸態(tài)(Zombie):進(jìn)程已完成執(zhí)行,但其父進(jìn)程尚未通過(guò) wait () 或 waitpid () 系統(tǒng)調(diào)用獲取其退出狀態(tài)并清理資源,因此進(jìn)程仍然保留著一個(gè)條目以供父進(jìn)程讀取其退出狀態(tài)。僵尸態(tài)進(jìn)程不會(huì)消耗任何 CPU 資源,但其進(jìn)程表項(xiàng)仍占用系統(tǒng)資源,長(zhǎng)時(shí)間存在可能會(huì)導(dǎo)致系統(tǒng)資源耗盡。例如,一個(gè)父進(jìn)程創(chuàng)建了多個(gè)子進(jìn)程,卻沒(méi)有正確處理子進(jìn)程的退出,就可能產(chǎn)生僵尸進(jìn)程。

圖片圖片

在多任務(wù)處理中,上下文切換發(fā)揮著至關(guān)重要的作用。它使得多個(gè)任務(wù)能夠公平、高效地共享CPU資源,從而提高系統(tǒng)的吞吐量和響應(yīng)時(shí)間。例如,當(dāng)你在電腦上同時(shí)打開(kāi)瀏覽器瀏覽網(wǎng)頁(yè)、播放音樂(lè)以及運(yùn)行文檔編輯軟件時(shí),操作系統(tǒng)通過(guò)上下文切換,在這些任務(wù)之間快速切換CPU的執(zhí)行權(quán),讓你感覺(jué)這些任務(wù)在同時(shí)進(jìn)行 。

然而,頻繁的上下文切換也會(huì)對(duì)CPU性能產(chǎn)生負(fù)面影響。這是因?yàn)槊看紊舷挛那袚Q都需要保存當(dāng)前任務(wù)的上下文信息,并加載新任務(wù)的上下文信息,這個(gè)過(guò)程涉及到 CPU 寄存器的讀寫、內(nèi)存訪問(wèn)等操作,會(huì)消耗一定的時(shí)間和CPU資源。過(guò)多的上下文切換,會(huì)占用CPU過(guò)多時(shí)間,縮短真正運(yùn)行時(shí)間,導(dǎo)致系統(tǒng)整體性能大幅下降。假設(shè)一個(gè)系統(tǒng)頻繁進(jìn)行上下文切換,CPU將大量時(shí)間耗費(fèi)在寄存器、內(nèi)核棧以及虛擬內(nèi)存等資源的保存和恢復(fù)上,真正用于執(zhí)行任務(wù)的時(shí)間就會(huì)減少,從而使得系統(tǒng)的運(yùn)行速度變慢,響應(yīng)延遲增加 。

那么,哪些因素可能導(dǎo)致上下文切換過(guò)多呢?系統(tǒng)中同時(shí)存在過(guò)多的進(jìn)程或線程,是一個(gè)常見(jiàn)的原因。當(dāng)進(jìn)程或線程數(shù)量超出 CPU 的處理能力時(shí),操作系統(tǒng)就需要頻繁地在它們之間進(jìn)行切換,以滿足每個(gè)任務(wù)的執(zhí)行需求。低優(yōu)先級(jí)進(jìn)程的競(jìng)爭(zhēng)也可能導(dǎo)致頻繁的上下文切換。如果多個(gè)低優(yōu)先級(jí)進(jìn)程在爭(zhēng)用 CPU 資源,操作系統(tǒng)為平衡負(fù)載而頻繁切換,也會(huì)增加上下文切換的次數(shù)。I/O 操作也是一個(gè)重要因素。當(dāng)進(jìn)程需要等待 I/O 操作(如磁盤讀寫或網(wǎng)絡(luò)請(qǐng)求)完成時(shí),會(huì)被掛起,操作系統(tǒng)會(huì)切換到其他進(jìn)程,若I/O操作非常頻繁,就會(huì)導(dǎo)致上下文切換頻繁發(fā)生 。

Part3.排查性能元兇

當(dāng)我們對(duì) CPU 性能指標(biāo)有了清晰認(rèn)識(shí)后,就需要借助一些強(qiáng)大的工具來(lái)排查那些導(dǎo)致 CPU 性能下降的 “元兇”。在 Linux 系統(tǒng)中,有許多實(shí)用工具,它們就像經(jīng)驗(yàn)豐富的偵探,能幫助我們從復(fù)雜的系統(tǒng)運(yùn)行狀態(tài)中找到問(wèn)題的關(guān)鍵所在 。

3.1 top與 htop

top 命令堪稱 Linux 系統(tǒng)性能監(jiān)控的 “元老”,它以簡(jiǎn)潔直觀的方式展示系統(tǒng)資源的實(shí)時(shí)使用情況,如同一位忠誠(chéng)的衛(wèi)士,時(shí)刻守護(hù)著系統(tǒng)的性能健康。在終端輸入 top,瞬間就能開(kāi)啟這場(chǎng)系統(tǒng)資源的 “實(shí)時(shí)之旅” 。

top 命令的輸出信息豐富而全面,第一行展示了系統(tǒng)的基本信息,包括當(dāng)前時(shí)間、系統(tǒng)運(yùn)行時(shí)長(zhǎng)、當(dāng)前登錄用戶數(shù)以及系統(tǒng)的平均負(fù)載(分別是過(guò)去 1 分鐘、5 分鐘和 15 分鐘的平均負(fù)載) 。這些信息就像系統(tǒng)的 “健康檔案”,為我們提供了一個(gè)宏觀的系統(tǒng)運(yùn)行概覽。平均負(fù)載是一個(gè)重要的指標(biāo),它反映了系統(tǒng)中正在運(yùn)行的進(jìn)程和等待運(yùn)行的進(jìn)程數(shù)量。如果平均負(fù)載持續(xù)高于系統(tǒng)的 CPU 核心數(shù),就像一個(gè)人同時(shí)承擔(dān)了過(guò)多的任務(wù),會(huì)導(dǎo)致系統(tǒng)運(yùn)行緩慢,響應(yīng)延遲 。

第二行呈現(xiàn)了系統(tǒng)的任務(wù)(進(jìn)程)信息,如進(jìn)程總數(shù)、正在運(yùn)行的進(jìn)程數(shù)、睡眠狀態(tài)的進(jìn)程數(shù)、停止?fàn)顟B(tài)的進(jìn)程數(shù)以及僵尸進(jìn)程數(shù) 。進(jìn)程是系統(tǒng)運(yùn)行的基本單元,了解進(jìn)程的狀態(tài)對(duì)于判斷系統(tǒng)性能至關(guān)重要。僵尸進(jìn)程是已經(jīng)結(jié)束運(yùn)行,但父進(jìn)程沒(méi)有正確回收其資源的進(jìn)程,它們雖然不占用 CPU 時(shí)間,但會(huì)占用系統(tǒng)資源,過(guò)多的僵尸進(jìn)程會(huì)導(dǎo)致系統(tǒng)資源浪費(fèi) 。

第三行則聚焦于 CPU 狀態(tài)信息,詳細(xì)列出了用戶空間占用 CPU 的百分比(us)、內(nèi)核空間占用CPU的百分比(sy)、改變過(guò)優(yōu)先級(jí)的進(jìn)程占用 CPU 的百分比(ni)、空閑CPU百分比(id)、IO 等待占用 CPU 的百分比(wa)、硬中斷占用 CPU 的百分比(hi)、軟中斷占用CPU的百分比(si)以及虛擬機(jī)偷取時(shí)間(st) 。這些指標(biāo)就像CPU的 “健康指標(biāo)”,通過(guò)它們,我們能深入了解 CPU 的工作狀態(tài)。當(dāng)us值較高時(shí),說(shuō)明用戶進(jìn)程消耗了大量的 CPU 資源,可能是某個(gè)用戶程序存在性能問(wèn)題,比如算法效率低下,需要頻繁進(jìn)行復(fù)雜的計(jì)算;sy 值高則表示系統(tǒng)內(nèi)核在 CPU 資源上的開(kāi)銷較大,這可能是由于頻繁的系統(tǒng)調(diào)用、大量的 I/O 操作或者內(nèi)核模塊的性能問(wèn)題導(dǎo)致的;wa 值高通常意味著系統(tǒng)在等待 I/O 操作完成,可能是磁盤讀寫速度過(guò)慢、網(wǎng)絡(luò)延遲過(guò)高或者 I/O 設(shè)備出現(xiàn)故障 。

除了這些基本信息,top命令還支持一些便捷的交互操作,讓我們能更靈活地監(jiān)控系統(tǒng)性能。按下大寫的“M”,結(jié)果會(huì)按照內(nèi)存占用從高到低排序,幫助我們快速找出占用內(nèi)存最多的進(jìn)程;按下大寫的“P”,則按照CPU占用率從高到低排序,讓 CPU 占用大戶無(wú)所遁形;當(dāng)服務(wù)器含有多個(gè) CPU 時(shí),按下數(shù)字 “1”,可以切換顯示各個(gè)CPU的詳細(xì)信息,讓我們能精準(zhǔn)了解每個(gè) CPU 核心的工作情況 。

如果說(shuō) top 命令是一位簡(jiǎn)潔高效的 “傳統(tǒng)偵探”,那么 htop 則是一位功能強(qiáng)大、更具交互性的 “現(xiàn)代神探”,它在 top 命令的基礎(chǔ)上進(jìn)行了全面升級(jí) 。htop 支持圖形界面的鼠標(biāo)操作,就像為我們提供了一個(gè)直觀的操作面板,讓我們能更輕松地與系統(tǒng)監(jiān)控界面交互 。它還可以橫向或縱向滾動(dòng)瀏覽進(jìn)程列表,即使面對(duì)長(zhǎng)長(zhǎng)的進(jìn)程列表和完整的命令行,也能輕松查看所有進(jìn)程信息,不放過(guò)任何一個(gè)細(xì)節(jié) 。在殺進(jìn)程時(shí),htop 無(wú)需像 top 那樣輸入繁瑣的進(jìn)程號(hào),只需輕松操作,就能快速結(jié)束目標(biāo)進(jìn)程 。

htop 的功能遠(yuǎn)不止這些。按下 F2 鍵,可以進(jìn)入設(shè)定布局界面,根據(jù)自己的需求調(diào)整監(jiān)控信息的顯示布局,讓監(jiān)控界面更符合個(gè)人使用習(xí)慣;按下 F3 鍵,能快速搜索進(jìn)程,就像在茫茫進(jìn)程海洋中找到了精準(zhǔn)定位的 “指南針”;按下 F4 鍵,可使用增量進(jìn)程過(guò)濾器,根據(jù)特定條件篩選出我們關(guān)注的進(jìn)程;按下 F5 鍵,能以樹(shù)形結(jié)構(gòu)顯示進(jìn)程關(guān)系,清晰呈現(xiàn)進(jìn)程之間的父子關(guān)系,幫助我們更好地理解系統(tǒng)的進(jìn)程架構(gòu);按下 F6 鍵,可以選擇排序方式,按照不同的指標(biāo)對(duì)進(jìn)程進(jìn)行排序,以便更方便地分析進(jìn)程的資源占用情況;按下 F7 和 F8 鍵,可以分別減少或增加進(jìn)程的 nice 值,從而調(diào)整進(jìn)程的優(yōu)先級(jí),合理分配系統(tǒng)資源;按下 F9 鍵,能對(duì)進(jìn)程傳遞信號(hào),實(shí)現(xiàn)對(duì)進(jìn)程的更多控制操作 。

在實(shí)際應(yīng)用中,top 和 htop 都有著廣泛的用途。在服務(wù)器運(yùn)維場(chǎng)景中,系統(tǒng)管理員可以通過(guò) top 實(shí)時(shí)監(jiān)控服務(wù)器的 CPU、內(nèi)存等資源使用情況,及時(shí)發(fā)現(xiàn)資源占用異常的進(jìn)程,如某個(gè)進(jìn)程突然占用大量 CPU 資源,導(dǎo)致服務(wù)器響應(yīng)變慢,管理員可以迅速通過(guò) top 或 htop 定位到該進(jìn)程,并采取相應(yīng)措施,如優(yōu)化程序代碼、調(diào)整進(jìn)程優(yōu)先級(jí)或者直接結(jié)束進(jìn)程,以保障服務(wù)器的穩(wěn)定運(yùn)行 。在開(kāi)發(fā)和測(cè)試環(huán)境中,開(kāi)發(fā)人員可以利用 htop 的強(qiáng)大交互功能,深入分析程序運(yùn)行時(shí)的資源占用情況,找出程序中的性能瓶頸,如某個(gè)函數(shù)在執(zhí)行過(guò)程中占用過(guò)多 CPU 時(shí)間,開(kāi)發(fā)人員可以針對(duì)該函數(shù)進(jìn)行優(yōu)化,提高程序的整體性能 。

3.2 vmstat 與 iostat

vmstat 命令如同一位深入系統(tǒng)內(nèi)部的 “探測(cè)器”,能夠提供關(guān)于進(jìn)程、內(nèi)存、內(nèi)存分頁(yè)、堵塞IO、traps及CPU 活動(dòng)的詳細(xì)信息,讓我們對(duì)系統(tǒng)的運(yùn)行狀態(tài)有更全面、深入的了解 。在終端輸入vmstat,即可開(kāi)啟這個(gè)系統(tǒng)狀態(tài)的深度探測(cè)之旅 。

vmstat 命令的輸出結(jié)果分為多個(gè)部分,每個(gè)部分都蘊(yùn)含著豐富的系統(tǒng)運(yùn)行信息 。procs 部分展示了進(jìn)程相關(guān)信息,其中 r 表示運(yùn)行隊(duì)列中進(jìn)程的數(shù)量,這些進(jìn)程都處于可運(yùn)行狀態(tài),正急切地等待 CPU 的分配 。當(dāng)這個(gè)值超過(guò)了 CPU 的核心數(shù)目,就如同眾多乘客爭(zhēng)搶有限的出租車,必然會(huì)出現(xiàn) CPU 瓶頸。此時(shí),系統(tǒng)的運(yùn)行效率會(huì)大幅下降,表現(xiàn)為程序響應(yīng)遲緩、操作卡頓等。b 表示被 blocked(阻塞)的進(jìn)程數(shù),這些進(jìn)程正在等待 IO 操作完成,就像在交通擁堵的路口等待通行的車輛,它們的存在也會(huì)影響系統(tǒng)的整體性能 。

memory 部分呈現(xiàn)了內(nèi)存的使用情況,swpd 表示使用的虛擬內(nèi)存的大小,如果該值大于 0,就像一個(gè)人在小房間里放置了過(guò)多的物品,說(shuō)明機(jī)器的物理內(nèi)存可能不足。這時(shí)候,我們需要進(jìn)一步排查原因,可能是程序存在內(nèi)存泄露問(wèn)題,也可能是系統(tǒng)本身的內(nèi)存配置無(wú)法滿足當(dāng)前的業(yè)務(wù)需求。free 表示可用的物理內(nèi)存大小,它反映了系統(tǒng)當(dāng)前還有多少 “空閑資源” 可供使用。buff 和 cache 分別表示物理內(nèi)存用來(lái)緩存讀寫操作的 buffer 大小以及用來(lái)緩存進(jìn)程地址空間的 cache 大小 。

合理利用buffer和cache可以提高系統(tǒng)的IO性能,因?yàn)樗鼈兛梢詼p少對(duì)磁盤的直接讀寫次數(shù)。當(dāng)程序需要讀取數(shù)據(jù)時(shí),首先會(huì)在 cache 中查找,如果找到,就可以直接從 cache 中讀取,而無(wú)需訪問(wèn)磁盤,大大提高了數(shù)據(jù)讀取速度;同樣,當(dāng)程序需要寫入數(shù)據(jù)時(shí),數(shù)據(jù)會(huì)先寫入 buffer,然后由系統(tǒng)在適當(dāng)?shù)臅r(shí)候?qū)?buffer 中的數(shù)據(jù)寫入磁盤,這樣可以減少磁盤的隨機(jī)寫入次數(shù),提高寫入效率 。

swap 部分展示了系統(tǒng)的交換空間使用情況,si 表示每秒從磁盤讀入虛擬內(nèi)存的大小,so 表示每秒虛擬內(nèi)存寫入磁盤的大小 。當(dāng)內(nèi)存夠用時(shí),這兩個(gè)值通常都是 0。但如果這兩個(gè)值長(zhǎng)期大于 0,就像在一個(gè)繁忙的港口,貨物頻繁地裝卸,說(shuō)明系統(tǒng)在頻繁地進(jìn)行內(nèi)存和磁盤之間的數(shù)據(jù)交換,這會(huì)嚴(yán)重影響系統(tǒng)性能 。

io 部分提供了輸入輸出信息,bi 表示每秒從文件系統(tǒng)或 SWAP 讀入到 RAM(blocks in)的塊數(shù),bo 表示每秒從 RAM 寫出到文件系統(tǒng)或 SWAP(blocks out)的塊數(shù) 。在隨機(jī)磁盤讀寫操作中,如果這兩個(gè)值越大(如超出 1024k),就像高速公路上的車流量過(guò)大,能看到 CPU 在 IO 等待的值也會(huì)越大,這表明系統(tǒng)的 IO 性能可能存在瓶頸 。

system 部分呈現(xiàn)了系統(tǒng)信息,in 表示每秒的中斷數(shù),cs 表示系統(tǒng)每秒進(jìn)行上下文切換的次數(shù) 。上下文切換是指 CPU 從一個(gè)進(jìn)程或線程切換到另一個(gè)進(jìn)程或線程的過(guò)程,這個(gè)過(guò)程需要保存和恢復(fù)進(jìn)程或線程的上下文信息,會(huì)消耗一定的 CPU 資源。因此,cs 值越小越好,如果上下文切換次數(shù)過(guò)多,就像一個(gè)人頻繁地在不同任務(wù)之間切換,會(huì)導(dǎo)致 CPU 大部分時(shí)間浪費(fèi)在上下文切換上,真正用于執(zhí)行任務(wù)的時(shí)間就會(huì)減少 。

cpu 部分展示了 CPU 活動(dòng)的相關(guān)信息,us 表示用戶空間占用 CPU 的百分比,當(dāng) us 的值較高時(shí),說(shuō)明用戶進(jìn)程消耗的 CPU 時(shí)間比較多,如果長(zhǎng)期超過(guò) 50%,就像一個(gè)員工承擔(dān)了過(guò)多的工作任務(wù),我們就需要考慮優(yōu)化程序算法或者進(jìn)行加速,以提高 CPU 的使用效率 。sy 表示內(nèi)核空間占用 CPU 的百分比,sy 值高時(shí),說(shuō)明系統(tǒng)內(nèi)核消耗的 CPU 資源多,這可能是由于頻繁的系統(tǒng)調(diào)用、大量的 I/O 操作或者內(nèi)核模塊的性能問(wèn)題導(dǎo)致的,需要進(jìn)一步排查原因 。

id 表示 CPU 空閑的百分比,它反映了 CPU 當(dāng)前的空閑程度 。wa 表示 CPU 等待 IO 的百分比,wa 值高時(shí),說(shuō)明 CPU 在等待 I/O 操作完成的時(shí)間比較多,這可能是由于大量的磁盤隨機(jī)訪問(wèn)造成的,也有可能是磁盤出現(xiàn)瓶頸,需要對(duì)磁盤性能進(jìn)行優(yōu)化 。st 表示來(lái)自于虛擬機(jī)偷取的 CPU 所占的百分比,在虛擬化環(huán)境中,這個(gè)指標(biāo)對(duì)于評(píng)估虛擬機(jī)對(duì)物理機(jī) CPU 資源的占用情況非常重要 。

iostat 命令則是專門用于監(jiān)控系統(tǒng)設(shè)備的 IO 負(fù)載情況的 “專家”,它能為我們提供豐富的 IO 性能狀態(tài)數(shù)據(jù),幫助我們準(zhǔn)確判斷系統(tǒng)的 IO 性能瓶頸 。iostat 首次運(yùn)行時(shí),會(huì)顯示自系統(tǒng)啟動(dòng)開(kāi)始的各項(xiàng)統(tǒng)計(jì)信息,之后運(yùn)行 iostat 將顯示自上次運(yùn)行該命令以后的統(tǒng)計(jì)信息 。我們可以通過(guò)指定統(tǒng)計(jì)的次數(shù)和時(shí)間來(lái)獲得所需的統(tǒng)計(jì)信息,非常靈活方便 。

iostat 命令的輸出結(jié)果主要包括 CPU 信息和磁盤信息兩個(gè)部分 。在 CPU 信息部分,% user 表示用戶態(tài) CPU 占用百分比,% nice 表示 nice 優(yōu)先級(jí)較高的進(jìn)程的 CPU 占用百分比,% system 表示系統(tǒng)態(tài) CPU 占用百分比,% iowait 表示等待 I/O 的 CPU 占用百分比,% steal 表示虛擬機(jī)監(jiān)控器占用的 CPU 時(shí)間百分比(僅在虛擬化環(huán)境中出現(xiàn)),% idle 表示 CPU 空閑百分比 。這些指標(biāo)與 vmstat 中 CPU 部分的指標(biāo)類似,但 iostat 的輸出更加專注于 CPU 與 IO 相關(guān)的性能情況 。當(dāng) % iowait 值較高時(shí),說(shuō)明 CPU 在等待 I/O 操作的時(shí)間較長(zhǎng),這可能是磁盤讀寫速度過(guò)慢、I/O 設(shè)備繁忙或者 I/O 調(diào)度不合理等原因?qū)е碌?。

磁盤信息部分是 iostat 命令的重點(diǎn),它詳細(xì)展示了每個(gè)磁盤設(shè)備的性能指標(biāo) 。Device 表示磁盤設(shè)備的名稱,tps 表示每秒傳輸?shù)膲K數(shù)量,它反映了磁盤的 I/O 操作頻率,就像高速公路上每秒通過(guò)的車輛數(shù) 。kB_read/s 表示每秒從設(shè)備讀取的數(shù)據(jù)量,kB_wrtn/s 表示每秒向設(shè)備寫入的數(shù)據(jù)量,這兩個(gè)指標(biāo)直觀地展示了磁盤的讀寫速度 。kB_read 和 kB_wrtn 分別表示讀取和寫入的總數(shù)據(jù)量 。

此外,iostat 還可以通過(guò) - x 選項(xiàng)顯示更詳細(xì)的擴(kuò)展數(shù)據(jù),如 rrqm/s 表示每秒這個(gè)設(shè)備相關(guān)的讀取請(qǐng)求有多少被 Merge 了,wrqm/s 表示每秒這個(gè)設(shè)備相關(guān)的寫入請(qǐng)求有多少被 Merge 了,rsec/s 和 wsec/s 分別表示每秒讀取和寫入的扇區(qū)數(shù),avgrq-sz 表示平均請(qǐng)求扇區(qū)的大小,avgqu-sz 表示平均請(qǐng)求隊(duì)列的長(zhǎng)度,await 表示每一個(gè) IO 請(qǐng)求的處理的平均時(shí)間,svctm 表示平均每次設(shè)備 I/O 操作的服務(wù)時(shí)間,% util 表示在統(tǒng)計(jì)時(shí)間內(nèi)所有處理 IO 時(shí)間除以總共統(tǒng)計(jì)時(shí)間,它反映了設(shè)備的繁忙程度 。當(dāng) % util 接近 100% 時(shí),說(shuō)明磁盤設(shè)備已經(jīng)接近滿負(fù)荷運(yùn)行,可能會(huì)出現(xiàn) I/O 性能瓶頸 。

在實(shí)際應(yīng)用中,vmstat 和 iostat 常用于排查系統(tǒng)性能問(wèn)題。當(dāng)系統(tǒng)出現(xiàn)卡頓、響應(yīng)遲緩等問(wèn)題時(shí),我們可以先使用 vmstat 查看系統(tǒng)的整體運(yùn)行狀態(tài),包括 CPU、內(nèi)存、IO 等方面的情況,初步判斷問(wèn)題所在 。如果發(fā)現(xiàn) CPU 等待 IO 的時(shí)間較長(zhǎng),或者內(nèi)存使用異常,就可以進(jìn)一步使用 iostat 命令來(lái)深入分析磁盤的 IO 性能,找出具體是哪個(gè)磁盤設(shè)備出現(xiàn)了問(wèn)題,以及問(wèn)題的具體表現(xiàn),如讀寫速度過(guò)慢、請(qǐng)求隊(duì)列過(guò)長(zhǎng)等 。通過(guò)這些工具的配合使用,我們能夠更準(zhǔn)確地定位系統(tǒng)性能問(wèn)題的根源,為后續(xù)的優(yōu)化工作提供有力支持 。

3.3 perf工具

perf工具堪稱Linux系統(tǒng)中 CPU 性能分析的 “手術(shù)刀”,它功能強(qiáng)大,能夠利用處理器硬件性能監(jiān)控單元進(jìn)行性能事件采樣,幫助我們深入剖析程序的性能瓶頸,精確找出進(jìn)程的熱點(diǎn)函數(shù),是解決CPU性能問(wèn)題的得力助手 。

perf 工具基于硬件性能計(jì)數(shù)器(Hardware Performance Counters,HPC)工作,這些計(jì)數(shù)器是 CPU 內(nèi)部的特殊寄存器,就像一個(gè)個(gè)精密的傳感器,能夠記錄特定事件的發(fā)生次數(shù) 。perf 通過(guò)與 Linux 內(nèi)核的 perf_event 子系統(tǒng)交互,讀取這些計(jì)數(shù)器的值,從而獲取程序運(yùn)行時(shí)的各種性能數(shù)據(jù),如 CPU 利用率、緩存命中率、指令執(zhí)行次數(shù)等 。

perf 工具提供了豐富多樣的子命令,每個(gè)子命令都有其獨(dú)特的功能,就像一把把不同的手術(shù)刀,適用于不同的性能分析場(chǎng)景 。

perf list 子命令用于列出當(dāng)前系統(tǒng)支持的硬件性能事件、軟件事件和跟蹤點(diǎn) 。這就像一本詳細(xì)的 “性能事件字典”,當(dāng)我們需要進(jìn)行特定的性能分析時(shí),可以先使用 perf list 查看系統(tǒng)支持的事件類型,以便選擇合適的事件進(jìn)行采樣和分析 。例如,我們想要分析網(wǎng)絡(luò)相關(guān)的性能問(wèn)題,可以使用 “perf list 'net:*'” 命令查看所有與網(wǎng)絡(luò)相關(guān)的事件 。

perf top 子命令能夠?qū)崟r(shí)動(dòng)態(tài)地顯示系統(tǒng)中 CPU 占用最高的函數(shù) 。它就像一個(gè)實(shí)時(shí)的 “性能放大鏡”,讓我們能夠直觀地看到當(dāng)前系統(tǒng)中哪些函數(shù)正在大量消耗 CPU 資源 。在實(shí)際應(yīng)用中,當(dāng)系統(tǒng)出現(xiàn) CPU 使用率過(guò)高的情況時(shí),我們可以通過(guò) perf top 快速定位到占用 CPU 資源最多的函數(shù),進(jìn)而深入分析這些函數(shù)的代碼邏輯,找出性能瓶頸所在 。比如,在一個(gè)大型數(shù)據(jù)庫(kù)應(yīng)用中,通過(guò) perf top 發(fā)現(xiàn)某個(gè)查詢函數(shù)占用了大量 CPU 時(shí)間,經(jīng)過(guò)進(jìn)一步分析,發(fā)現(xiàn)是該函數(shù)中的查詢語(yǔ)句沒(méi)有使用合適的索引,導(dǎo)致全表掃描,從而消耗了大量 CPU 資源 。通過(guò)優(yōu)化查詢語(yǔ)句,添加合適的索引,成功降低了該函數(shù)的 CPU 占用率,提高了系統(tǒng)性能 。

perf stat 子命令用于統(tǒng)計(jì)程序運(yùn)行時(shí)的硬件事件,如緩存未命中、分支預(yù)測(cè)錯(cuò)誤等 。它就像一個(gè)精準(zhǔn)的 “性能計(jì)數(shù)器”,能夠幫助我們了解程序在運(yùn)行過(guò)程中的各種硬件事件發(fā)生情況 。通過(guò)分析這些事件的統(tǒng)計(jì)數(shù)據(jù),我們可以評(píng)估程序?qū)τ布Y源的利用效率,找出可能存在的性能問(wèn)題 。例如,我們可以使用 “perf stat -a -r 3 sleep 5” 命令對(duì)系統(tǒng)進(jìn)行全局統(tǒng)計(jì),統(tǒng)計(jì) 5 秒內(nèi)的硬件事件,并重復(fù) 3 次 。在輸出結(jié)果中,我們可以看到諸如 “cpu-clock”(CPU 時(shí)鐘周期)、“context-switches”(上下文切換次數(shù))、“page-faults”(頁(yè)面錯(cuò)誤次數(shù))等硬件事件的統(tǒng)計(jì)信息 。如果發(fā)現(xiàn)緩存未命中次數(shù)過(guò)高,說(shuō)明程序?qū)彺娴睦眯瘦^低,可能需要優(yōu)化程序的內(nèi)存訪問(wèn)模式,以提高緩存命中率 。

perf record 子命令用于記錄程序運(yùn)行時(shí)的性能事件,并將這些事件保存到一個(gè)文件(默認(rèn)為 perf.data)中,以便后續(xù)進(jìn)行詳細(xì)的性能分析 。它就像一個(gè)忠實(shí)的 “記錄員”,能夠準(zhǔn)確地記錄程序運(yùn)行時(shí)的各種性能細(xì)節(jié) 。我們可以使用 “perf record -g -F 99 -p 5678” 命令記錄 PID 為 5678 的進(jìn)程的調(diào)用圖,每秒采樣 99 次 。這樣,在程序運(yùn)行結(jié)束后,我們就可以通過(guò)其他子命令對(duì)保存的性能數(shù)據(jù)進(jìn)行分析 。

perf report 子命令用于分析 perf record 保存的性能事件,生成詳細(xì)的性能報(bào)告 。它就像一個(gè)專業(yè)的 “分析師”,能夠?qū)τ涗浀男阅軘?shù)據(jù)進(jìn)行深入解讀,展示程序中各個(gè)函數(shù)的性能消耗情況 。我們可以使用 “perf report -n --stdio” 命令以文本模式顯示樣本數(shù)量,也可以使用 “perf report -s symbol” 命令按函數(shù)名排序,以便更清晰地查看各個(gè)函數(shù)的性能情況 。在性能報(bào)告中,我們可以看到每個(gè)函數(shù)的 CPU 占用百分比、調(diào)用次數(shù)等信息,從而快速找出性能瓶頸所在的函數(shù) 。

perf script 子命令用于導(dǎo)出原始數(shù)據(jù),將 perf.data 文件轉(zhuǎn)換為文本格式 。這對(duì)于生成火焰圖或進(jìn)行自定義分析非常有用 ?;鹧鎴D是一種直觀展示程序性能的工具,它能夠以圖形化的方式呈現(xiàn)函數(shù)的調(diào)用關(guān)系和 CPU 占用情況 。我們可以使用 “perf script> out.stack” 命令將 perf.data 文件中的數(shù)據(jù)導(dǎo)出為調(diào)用棧數(shù)據(jù),然后使用相關(guān)工具生成火焰圖 。通過(guò)火焰圖,我們可以更直觀地看到程序中哪些函數(shù)調(diào)用頻繁,哪些函數(shù)占用 CPU 時(shí)間較長(zhǎng),從而有針對(duì)性地進(jìn)行性能優(yōu)化 。

在實(shí)際使用perf工具時(shí),我們可以根據(jù)具體的性能分析需求,靈活組合使用這些子命令 。例如,當(dāng)我們懷疑某個(gè)程序存在性能問(wèn)題時(shí),可以先使用perf top實(shí)時(shí)查看該程序中占用CPU資源最多的函數(shù),初步定位性能瓶頸 。然后,使用perfrecord記錄該程序運(yùn)行時(shí)的性能事件,并使用perf report對(duì)記錄的數(shù)據(jù)進(jìn)行分析,深入了解各個(gè)函數(shù)的性能消耗情況 。如果需要進(jìn)一步分析函數(shù)的調(diào)用關(guān)系和CPU占用的詳細(xì)情況,可以使用perf script導(dǎo)出原始數(shù)據(jù),生成火焰圖進(jìn)行分析 。

3.4 圖形化工具

Process Explorer:這是一款 Windows 系統(tǒng)下非常強(qiáng)大的進(jìn)程管理工具 。它可以顯示系統(tǒng)中所有進(jìn)程的詳細(xì)信息,包括進(jìn)程的名稱、描述、路徑、公司信息、CPU 占用率、GPU 占用率以及進(jìn)程關(guān)聯(lián)的子進(jìn)程等 。通過(guò) Process Explorer,我們可以直觀地看到每個(gè)進(jìn)程的資源使用情況,并且可以方便地對(duì)進(jìn)程進(jìn)行各種操作,如結(jié)束進(jìn)程、查看進(jìn)程屬性、分析進(jìn)程的依賴關(guān)系等 。

例如,當(dāng)我們懷疑某個(gè)進(jìn)程占用了過(guò)高的 CPU 資源時(shí),可以在 Process Explorer 中找到該進(jìn)程,然后查看它的詳細(xì)信息,了解它的運(yùn)行狀態(tài)和資源使用情況。此外,Process Explorer 還可以監(jiān)控進(jìn)程訪問(wèn)的網(wǎng)絡(luò)地址和打開(kāi)的句柄信息,這對(duì)于檢測(cè)潛在的系統(tǒng)問(wèn)題、找出系統(tǒng)中的惡意軟件或病毒等非常有幫助。

Gnome System Monitor:這是 Linux 系統(tǒng)中 GNOME 桌面環(huán)境下的一個(gè)系統(tǒng)監(jiān)控工具 。它可以顯示最近一段時(shí)間內(nèi)的 CPU、內(nèi)存、交換區(qū)及網(wǎng)絡(luò)的使用情況 。通過(guò) Gnome System Monitor,我們可以以圖形化的方式直觀地了解系統(tǒng)的資源使用情況,并且可以方便地查看每個(gè)進(jìn)程的 CPU 占用率、內(nèi)存使用量等信息 。

例如,在 Gnome System Monitor 的界面中,我們可以看到一個(gè)實(shí)時(shí)更新的 CPU 使用情況圖表,通過(guò)這個(gè)圖表,我們可以很直觀地看到 CPU 的使用率變化情況。同時(shí),我們還可以在進(jìn)程列表中查看每個(gè)進(jìn)程的詳細(xì)信息,對(duì)進(jìn)程進(jìn)行管理和監(jiān)控。

Part4.CPU占用率過(guò)高案例分析

當(dāng)我們通過(guò)工具初步確定了 CPU 占用率過(guò)高的問(wèn)題后,就需要進(jìn)一步深入排查,找出問(wèn)題的根源。這就像是醫(yī)生給病人看病,僅僅知道病人發(fā)燒是不夠的,還需要通過(guò)各種檢查手段找出發(fā)燒的原因,是感冒、炎癥還是其他疾病。

4.1 定位問(wèn)題進(jìn)程

在使用 top、htop 等工具確定了占用 CPU 過(guò)高的進(jìn)程后,我們可以使用一些命令來(lái)獲取該進(jìn)程的更多詳細(xì)信息。例如,使用 “ps -ef | grep 進(jìn)程名” 命令可以查看該進(jìn)程的詳細(xì)信息,包括進(jìn)程 ID、用戶、啟動(dòng)時(shí)間、命令行等 。通過(guò)這些信息,我們可以初步判斷該進(jìn)程是否是正常運(yùn)行的進(jìn)程,還是可能存在問(wèn)題的進(jìn)程。比如,我們發(fā)現(xiàn)一個(gè)名為 “java” 的進(jìn)程占用了大量 CPU 資源,通過(guò) “ps -ef | grep java” 命令查看其詳細(xì)信息,發(fā)現(xiàn)它是一個(gè)正在運(yùn)行的 Java 應(yīng)用程序,并且啟動(dòng)時(shí)間是最近,這可能意味著這個(gè) Java 應(yīng)用程序出現(xiàn)了問(wèn)題,導(dǎo)致 CPU 占用過(guò)高。

4.2 分析進(jìn)程線程

一個(gè)進(jìn)程可能包含多個(gè)線程,而導(dǎo)致 CPU 占用過(guò)高的可能只是其中的一個(gè)或幾個(gè)線程。因此,我們需要進(jìn)一步分析進(jìn)程內(nèi)各個(gè)線程的 CPU 占用情況 。在 Linux 系統(tǒng)中,我們可以使用 “top -H -p 進(jìn)程 ID” 命令來(lái)查看指定進(jìn)程內(nèi)各個(gè)線程的 CPU 占用情況 。這個(gè)命令會(huì)以線程為單位顯示 CPU 使用率等信息,讓我們可以直觀地看到哪個(gè)線程占用了大量的 CPU 資源。

例如,對(duì)于前面提到的占用 CPU 過(guò)高的 Java 進(jìn)程,我們使用 “top -H -p 12345”(假設(shè)該 Java 進(jìn)程的 ID 為 12345)命令,發(fā)現(xiàn)其中一個(gè)線程的 CPU 使用率高達(dá) 90%,那么這個(gè)線程很可能就是導(dǎo)致 CPU 占用過(guò)高的原因。

在Windows系統(tǒng)中,我們可以使用Process Explorer 工具來(lái)查看進(jìn)程內(nèi)各個(gè)線程的 CPU 占用情況。在Process Explorer 的界面中,展開(kāi)進(jìn)程節(jié)點(diǎn),就可以看到該進(jìn)程包含的所有線程,并且可以查看每個(gè)線程的 CPU 使用率、線程 ID 等信息 。

4.3 深入代碼層級(jí)

如果通過(guò)線程分析還是無(wú)法確定問(wèn)題的根源,我們就需要深入到代碼層級(jí)進(jìn)行分析。這時(shí)候,我們可以使用一些調(diào)試工具,如 GDB(GNU Debugger)、WinDBG(Windows Debugger)等 。這些工具可以幫助我們調(diào)試程序,查看程序的執(zhí)行狀態(tài)、變量值、調(diào)用堆棧等信息,從而找出代碼中的性能瓶頸。

以 GDB 為例,我們可以使用以下步驟來(lái)分析代碼:

  1. 啟動(dòng) GDB:在終端中輸入 “gdb 可執(zhí)行文件路徑”,啟動(dòng) GDB 調(diào)試器,并加載需要調(diào)試的程序。
  2. 設(shè)置斷點(diǎn):使用 “break 行號(hào)” 或 “break 函數(shù)名” 命令在代碼中設(shè)置斷點(diǎn),當(dāng)程序執(zhí)行到斷點(diǎn)處時(shí)會(huì)暫停執(zhí)行,方便我們查看程序狀態(tài)。
  3. 運(yùn)行程序:使用 “run” 命令運(yùn)行程序,程序會(huì)在設(shè)置的斷點(diǎn)處暫停。
  4. 查看程序狀態(tài):使用 “print 變量名” 命令查看變量的值,使用 “backtrace” 命令查看調(diào)用堆棧,了解程序的執(zhí)行流程和函數(shù)調(diào)用關(guān)系 。
  5. 單步執(zhí)行:使用 “next” 命令單步執(zhí)行代碼,逐行查看程序的執(zhí)行情況,觀察變量的變化和函數(shù)的調(diào)用,找出可能導(dǎo)致 CPU 占用過(guò)高的代碼段。

假設(shè)我們有一個(gè) C++ 程序,通過(guò)前面的排查發(fā)現(xiàn)某個(gè)函數(shù)可能存在性能問(wèn)題。我們使用 GDB 進(jìn)行調(diào)試,在該函數(shù)中設(shè)置斷點(diǎn),運(yùn)行程序后,程序在斷點(diǎn)處暫停。通過(guò)查看調(diào)用堆棧,我們發(fā)現(xiàn)該函數(shù)被頻繁調(diào)用,并且在函數(shù)內(nèi)部有一個(gè)循環(huán),循環(huán)體中的計(jì)算量很大,這很可能就是導(dǎo)致 CPU 占用過(guò)高的原因。

4.4 常見(jiàn)原因大剖析

(1)代碼層面

①死循環(huán):死循環(huán)是導(dǎo)致 CPU 占用過(guò)高的常見(jiàn)原因之一。當(dāng)程序進(jìn)入死循環(huán)時(shí),會(huì)不斷重復(fù)執(zhí)行循環(huán)體中的代碼,無(wú)法跳出循環(huán),從而使 CPU 一直處于忙碌狀態(tài) 。例如,在下面這段 C++ 代碼中:

while (true) {
    // 這里沒(méi)有任何能使循環(huán)結(jié)束的條件
}

這個(gè) while 循環(huán)的條件始終為 true,程序會(huì)一直執(zhí)行這個(gè)循環(huán),導(dǎo)致 CPU 占用率急劇上升 。在實(shí)際開(kāi)發(fā)中,死循環(huán)可能是由于邏輯錯(cuò)誤、未正確設(shè)置循環(huán)結(jié)束條件等原因?qū)е碌?。比如在一個(gè)文件讀取的循環(huán)中,原本應(yīng)該在讀取完文件后結(jié)束循環(huán),但如果判斷文件結(jié)束的條件寫錯(cuò),就可能導(dǎo)致死循環(huán)。

②低效算法:算法的效率對(duì) CPU 的使用有著重要影響。如果算法的時(shí)間復(fù)雜度較高,在處理大量數(shù)據(jù)時(shí),就會(huì)消耗大量的 CPU 資源 。以冒泡排序算法為例,它的時(shí)間復(fù)雜度為 O (n^2) ,對(duì)于大規(guī)模數(shù)據(jù)的排序效率較低。當(dāng)需要排序的數(shù)據(jù)量很大時(shí),使用冒泡排序會(huì)使 CPU 長(zhǎng)時(shí)間處于高負(fù)載狀態(tài) 。而快速排序算法的平均時(shí)間復(fù)雜度為 O (nlogn) ,相比冒泡排序,在處理大數(shù)據(jù)集時(shí)效率更高,對(duì) CPU 的占用也相對(duì)較低。因此,在選擇算法時(shí),需要根據(jù)具體的應(yīng)用場(chǎng)景和數(shù)據(jù)規(guī)模,選擇合適的高效算法,以減少 CPU 的消耗。

③頻繁系統(tǒng)調(diào)用:系統(tǒng)調(diào)用是程序與操作系統(tǒng)內(nèi)核進(jìn)行交互的方式,每次系統(tǒng)調(diào)用都需要進(jìn)行用戶態(tài)到內(nèi)核態(tài)的切換,這個(gè)過(guò)程會(huì)消耗一定的 CPU 資源 。如果程序中頻繁進(jìn)行系統(tǒng)調(diào)用,就會(huì)導(dǎo)致 CPU 在用戶態(tài)和內(nèi)核態(tài)之間頻繁切換,從而增加 CPU 的負(fù)擔(dān) 。例如,在一個(gè)文件操作頻繁的程序中,如果每次讀取文件都進(jìn)行一次系統(tǒng)調(diào)用,而不是批量讀取,就會(huì)導(dǎo)致系統(tǒng)調(diào)用次數(shù)過(guò)多,占用大量 CPU 資源 。在網(wǎng)絡(luò)編程中,如果頻繁進(jìn)行網(wǎng)絡(luò)連接的建立和關(guān)閉操作,也會(huì)因?yàn)轭l繁的系統(tǒng)調(diào)用而使 CPU 占用率升高。

(2)系統(tǒng)層面
  • 內(nèi)存不足:當(dāng)系統(tǒng)內(nèi)存不足時(shí),操作系統(tǒng)會(huì)將一部分內(nèi)存數(shù)據(jù)交換到磁盤上的虛擬內(nèi)存中 。而虛擬內(nèi)存的讀寫速度比物理內(nèi)存慢很多,這就導(dǎo)致 CPU 需要花費(fèi)更多的時(shí)間等待數(shù)據(jù)的讀寫,從而使 CPU 占用率升高 。例如,當(dāng)一個(gè)程序需要處理大量數(shù)據(jù),但系統(tǒng)內(nèi)存無(wú)法容納這些數(shù)據(jù)時(shí),就會(huì)發(fā)生內(nèi)存交換,CPU 需要不斷地等待數(shù)據(jù)從磁盤的虛擬內(nèi)存中讀取到物理內(nèi)存,這會(huì)嚴(yán)重影響系統(tǒng)性能,導(dǎo)致 CPU 占用率居高不下 。為了解決內(nèi)存不足導(dǎo)致的 CPU 占用過(guò)高問(wèn)題,可以通過(guò)增加物理內(nèi)存、優(yōu)化程序的內(nèi)存使用等方式來(lái)緩解。
  • 磁盤 I/O 瓶頸:如果磁盤的讀寫速度較慢,或者磁盤 I/O 操作過(guò)于頻繁,就會(huì)形成磁盤 I/O 瓶頸 。當(dāng)程序需要頻繁讀取或?qū)懭氪疟P數(shù)據(jù)時(shí),會(huì)因?yàn)榇疟P I/O 的延遲而使 CPU 處于等待狀態(tài),導(dǎo)致 CPU 利用率下降,但同時(shí) CPU 占用率卻可能升高 。比如在一個(gè)數(shù)據(jù)庫(kù)應(yīng)用中,如果數(shù)據(jù)庫(kù)文件存儲(chǔ)在低速磁盤上,并且頻繁進(jìn)行數(shù)據(jù)的讀寫操作,就可能出現(xiàn)磁盤 I/O 瓶頸,使 CPU 占用率升高 。為了解決磁盤 I/O 瓶頸問(wèn)題,可以考慮升級(jí)磁盤設(shè)備,使用更快的固態(tài)硬盤(SSD),或者優(yōu)化程序的磁盤 I/O 操作,減少不必要的磁盤讀寫。
  • 惡意軟件:惡意軟件如病毒、木馬等可能會(huì)在后臺(tái)運(yùn)行大量的惡意進(jìn)程,占用大量的 CPU 資源 。這些惡意軟件可能會(huì)進(jìn)行加密貨幣挖礦、發(fā)送垃圾郵件、傳播惡意程序等惡意活動(dòng),導(dǎo)致系統(tǒng)性能急劇下降 。例如,某些挖礦病毒會(huì)利用計(jì)算機(jī)的 CPU 資源進(jìn)行虛擬貨幣的挖掘,使 CPU 一直處于高負(fù)載運(yùn)行狀態(tài),不僅占用大量 CPU 資源,還會(huì)導(dǎo)致系統(tǒng)過(guò)熱 。為了防范惡意軟件,我們需要安裝可靠的殺毒軟件和防火墻,定期進(jìn)行系統(tǒng)掃描,及時(shí)發(fā)現(xiàn)和清除惡意軟件。

4.5 實(shí)戰(zhàn)演練:模擬排查全過(guò)程

為了讓大家更清楚地了解排查 CPU 占用率過(guò)高問(wèn)題的過(guò)程,我們來(lái)模擬一個(gè)具體的場(chǎng)景。假設(shè)我們有一臺(tái)運(yùn)行著多個(gè)服務(wù)的 Linux 服務(wù)器,最近用戶反饋系統(tǒng)響應(yīng)非常緩慢,通過(guò)監(jiān)控工具發(fā)現(xiàn)服務(wù)器的 CPU 占用率長(zhǎng)期維持在 90% 以上 ,嚴(yán)重影響了業(yè)務(wù)的正常運(yùn)行。接下來(lái),我們就按照前面介紹的排查步驟來(lái)解決這個(gè)問(wèn)題。

①使用 top 命令定位問(wèn)題進(jìn)程:在終端中輸入 “top” 命令,按下回車鍵后,我們看到系統(tǒng)中各個(gè)進(jìn)程的資源使用情況。通過(guò)觀察發(fā)現(xiàn),一個(gè)名為 “my_service” 的進(jìn)程占用了大量的 CPU 資源,其 CPU 使用率高達(dá) 80% 。

top - 16:23:05 up 2 days,  3:15,  3 users,  load average: 0.95, 0.85, 0.75
Tasks: 250 total,   2 running, 248 sleeping,   0 stopped,   0 zombie
%Cpu(s): 80.3 us,  9.3 sy,  0.0 ni, 10.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  3251276 total,   456896 free,  1896432 used,   900948 buff/cache
KiB Swap:  4194300 total,  4194300 free,        0 used.  1345672 avail Mem 

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
12345 root      20   0  567890 234567  12345 R  80.0  7.2   0:20.00 my_service

②分析進(jìn)程線程:確定了 “my_service” 進(jìn)程占用 CPU 過(guò)高后,我們使用 “top -H -p 12345”(假設(shè) “my_service” 進(jìn)程的 ID 為 12345)命令來(lái)查看該進(jìn)程內(nèi)各個(gè)線程的 CPU 占用情況 。發(fā)現(xiàn)其中一個(gè)線程(線程 ID 為 12346)的 CPU 使用率高達(dá) 75% ,很可能就是這個(gè)線程導(dǎo)致了 CPU 占用過(guò)高。

top - 16:25:05 up 2 days,  3:17,  3 users,  load average: 0.98, 0.88, 0.78
Threads:  50 total,   2 running,  48 sleeping,   0 stopped,   0 zombie
%Cpu(s): 80.3 us,  9.3 sy,  0.0 ni, 10.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  3251276 total,   456896 free,  1896432 used,   900948 buff/cache
KiB Swap:  4194300 total,  4194300 free,        0 used.  1345672 avail Mem 

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
12346 root      20   0  567890 234567  12345 R  75.0  7.2   0:15.00 my_service

③深入代碼層級(jí):由于 “my_service” 是我們自己開(kāi)發(fā)的服務(wù),我們決定使用 GDB 進(jìn)行調(diào)試。首先,使用 “gdb /path/to/my_service 12345” 命令啟動(dòng) GDB 并加載 “my_service” 進(jìn)程 。然后,在 GDB 中使用 “thread 12346” 命令切換到占用 CPU 過(guò)高的線程 。接著,使用 “bt” 命令查看該線程的調(diào)用堆棧,發(fā)現(xiàn)它一直在調(diào)用一個(gè)名為 “process_data” 的函數(shù)。

(gdb) thread 12346
[Switching to thread 12346 (LWP 12346)]
(gdb) bt
#0  process_data () at /path/to/src/my_service.c:123
#1  0x0000000000401234 in main () at /path/to/src/my_service.c:234

④查看代碼找出問(wèn)題:打開(kāi) “my_service.c” 文件,查看第 123 行的 “process_data” 函數(shù)代碼,發(fā)現(xiàn)其中有一個(gè)死循環(huán),導(dǎo)致線程一直在執(zhí)行該循環(huán),無(wú)法跳出,從而占用了大量的 CPU 資源。

void process_data() {
    while (true) {
        // 這里沒(méi)有任何能使循環(huán)結(jié)束的條件,導(dǎo)致死循環(huán)
        // 一些復(fù)雜的計(jì)算操作
    }
}

⑤解決問(wèn)題:修改 “process_data” 函數(shù)的代碼,添加正確的循環(huán)結(jié)束條件,修復(fù)死循環(huán)問(wèn)題。重新編譯并部署 “my_service” 服務(wù)后,再次使用 top 命令查看 CPU 占用情況,發(fā)現(xiàn) “my_service” 進(jìn)程的 CPU 使用率已經(jīng)降下來(lái)了,系統(tǒng)恢復(fù)正常運(yùn)行。

通過(guò)這個(gè)模擬案例,我們可以看到,排查 CPU 占用率過(guò)高問(wèn)題需要我們熟練掌握各種排查工具和方法,從系統(tǒng)層面逐步深入到代碼層面,耐心細(xì)致地分析問(wèn)題,最終找到并解決問(wèn)題的根源。

責(zé)任編輯:武曉燕 來(lái)源: 深度Linux
相關(guān)推薦

2019-07-16 06:43:18

LinuxCPU占用率

2020-12-20 10:37:06

Windows10操作系統(tǒng)CPU

2019-07-24 11:52:11

CPU服務(wù)器面試官

2009-08-13 17:53:59

控制CPU占用率

2020-11-02 09:25:33

CPUJava線程

2021-05-12 21:10:22

Windows10操作系統(tǒng)微軟

2022-10-10 09:10:07

命令磁盤排查

2021-05-14 09:41:16

Windows 功能系統(tǒng)

2019-04-29 14:23:46

Java服務(wù)器CPU

2019-03-07 09:25:59

LinuxCPU交換分區(qū)

2016-09-21 12:26:47

Windows 10CPU禁用

2025-08-28 09:21:25

2025-06-16 03:22:00

2025-08-21 13:40:58

頭文件循環(huán)項(xiàng)目

2025-05-29 10:30:00

C++編程recv

2024-10-21 00:00:01

Linux服務(wù)器CPU

2020-09-28 13:54:12

Chrome OSChromebook更新

2019-09-17 13:00:54

Windows 10微軟CPU

2025-08-18 02:11:00

2025-08-11 05:00:00

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)