關於CPU使用率飆升,我們需要了解什麼?

2021-02-13 21ic電子網

CPU% = (1 - idleTime / sysTime) * 100

2、CPU 使用率跟啥有關係?

常聽說計算密集型的程序是比較耗 CPU 使用率的。

3、CPU 與進程、線程有關係麼?

現在分時作業系統是通過循輪方式分配時間片進行進程調度的,如果進程在等待或阻塞,不會造成 CPU 資源使用。線程稱為輕進程,共享進程資源,關於線程的調度,CPU 對於線程也是分時調度。而在 Java 中,線程的調用由 JVM 負責,線程的調度一般有兩種模式,分時調度和搶佔式調度。



4、一個 while 死循環,會不會引起 CPU 使用率飈升?

會的。

先不說別的,死循環會調用 CPU 寄存器進行計數,這個操作就會佔用 CPU。其次,如果線程一直處於死循環狀態,CPU 調用會進行線程切換麼?

死循環不會讓出 CPU,除非作業系統時間片到期,但死循環會不斷向系統申請時間片,直到系統沒有空閒時間做別的事情。

這個問題在 stackoverflow 也有人提問:why does an infinite loop of the unintended kind increase the CPU use?

地址:https://stackoverflow.com/questions/2846165/why-does-an-infinite-loop-of-the-unintended-kind-increase-the-cpu-use

5、頻繁 Young GC 會不會引起 CPU 使用率飈升?

會的。

Young GC 本身是 JVM 進行垃圾回收的操作,會計算內存和調用寄存器,頻繁 Young GC 一定是會佔用 CPU。

之前有個一個案例,for 循環從資料庫查詢數據集合,二次封裝新的數據集合,這時如果量比較大時,內存沒有足夠的空間存儲,那麼 JVM 就會 GC 回收那些不再使用的數據,因此量大的時候,就會收到 CPU 使用率報警。

6、線程數很高的應用,CPU 使用率一定高麼?

不會。

通過 jstack 查看系統線程狀態,查看整個線程數很多,但 Runable 和 Running 狀態的線程不多,這時 CPU 使用率不一定會高。

之前有過一個案例,查看系統線程數 1000+,jstack 分析 900多個線程是 BLOCKED 和 WAITING 狀態的,這種線程是不會佔用 CPU 的。

如果線程數很高,其實大多數原因是死鎖,大量線程處於 BLOCKED 和 WAITING 狀態。

7、CPU 使用率高的應用,線程數一定高麼?

不會。

同上,CPU 使用率高的關鍵因素還是計算密集型操作,一個線程如果有大量計算,也會造成 CPU 使用率高,也是現在為什麼一個大數據腳本任務,要大規模集群共同運算才能運行的原因。

8、BLOCKED 狀態的線程會不會引起 CPU 使用率飈升?

不一定。

CPU使用率的飆升,更多是因為上下文的切換或者runnable狀態線程過多導致。Blocked狀態,未必會引起CPU上升。

9、分時作業系統 CPU us高或者sy高是什麼意思?

通過top命令,可以觀察到CPU的us,sy值,示例如下:

CPU飆升線程定位示例:

public class cpuTest {
public static void main(String args[]){
for(int i=0;i<10;i++){
new Thread(){
public void run(){
try{
Thread.sleep(100000);
}catch(Exception e){}
}
}.start();
}
Thread t=new Thread(){
public void run(){
int i=0;
while(true){
i=(i++)/100;
}
}
};
t.setName("Busiest Thread");
t.start();
}
}

步驟1: 執行top -c ,顯示進程運行信息列表,鍵入P (大寫p),進程按照CPU使用率排序,最耗CPU的進程PID為18207

步驟2:首先我們可以通過top -Hp <pid>來看這個進程裡所有線程的cpu消耗情況

$ top -Hp 18207top - 19:11:43 up 573 days,  2:43,  2 users,  load average: 3.03, 3.03, 3.02Tasks:  44 total,   1 running,  43 sleeping,   0 stopped,   0 zombieCpu(s): 18.8%us,  0.0%sy,  0.0%ni, 81.1%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%stMem:  99191752k total, 98683576k used,   508176k free,   128248k buffersSwap:  1999864k total,   191064k used,  1808800k free, 17413760k cached PID  USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND18250 admin     20   0 26.1g  28m  10m R 99.9  0.0   0:19.50 java Test18207 admin     20   0 26.1g  28m  10m S  0.0  0.0   0:00.00 java Test18208 admin     20   0 26.1g  28m  10m S  0.0  0.0   0:00.09 java Test18209 admin     20   0 26.1g  28m  10m S  0.0  0.0   0:00.00 java Test18210 admin     20   0 26.1g  28m  10m S  0.0  0.0   0:00.00 java Test18211 admin     20   0 26.1g  28m  10m S  0.0  0.0   0:00.00 java

cpu最高的線程是pid為18250的線程,佔了99.9%

步驟3:printf 「%x\n」 18250將線程PID轉化為16進位

$ printf 「%x\n」 18250

0X47A

...

步驟4:jstack 18207|grep'0X47A'-C5 --color找出進程中消耗CPU最多的線程棧

$ jstack 18207|grep'0X47A'-C5 --colorFull thread dump OpenJDK 64-Bit Server VM (25.66-b60 mixed mode):"Attach Listener" #30 daemon prio=9 os_prio=0 tid=0x00007fb90be13000 nid=0x47d7 waiting on condition [0x0000000000000000]   java.lang.Thread.State: RUNNABLE"DestroyJavaVM" #29 prio=5 os_prio=0 tid=0x00007fb96245b800 nid=0x4720 waiting on condition [0x0000000000000000]   java.lang.Thread.State: RUNNABLE"Busiest Thread" #28 prio=5 os_prio=0 tid=0x00007fb91498d000 nid=0x474a runnable [0x00007fb9065fe000]   java.lang.Thread.State: RUNNABLE    at Test$2.run(Test.java:18)"Thread-9" #27 prio=5 os_prio=0 tid=0x00007fb91498c800 nid=0x4749 waiting on condition [0x00007fb906bfe000]   java.lang.Thread.State: TIMED_WAITING (sleeping)    at java.lang.Thread.sleep(Native Method)    at Test$1.run(Test.java:9)...

因此,最耗cpu的線程是Busiest Thread

日常程序中常見的耗CPU的操作:

1、頻繁GC,訪問量高時,有可能造成頻繁的GC、甚至FGC。當調用量大時,內存分配過快,就會造成GC線程不停的執行,導致CPU飆高

2、序列化與反序列化,後文中舉了一個真實的案例,程序執行xml解析的時,調用量增大的情況下,導致了CPU被打滿

3、加密解密

4、正則表達式校驗,曾經線上發生一次血案,正則校驗將CPU打滿。大概原因是:Java 正則表達式使用的引擎實現是 NFA 自動機,這種引擎在進行字符匹配會發生回溯(backtracking)

5、線程上下文切換、當啟動了很多線程,而這些線程都處於不斷的阻塞狀態(鎖等待、IO等待等)和執行狀態的變化過程中。當鎖競爭激烈時,很容易出現這種情況

6、某些線程在做無阻塞的運算,簡單的例子while(true)中不停的做運算,沒有任何阻塞。寫程序時,如果需要做很久的計算,可以適當將程序sleep下

7、Excel 導出事件

頻繁GC案例

案例背景:網關服務進行控制單個url訪問次數限流,CPU過若干天后飆升到80%,重啟服務過若干天后又再次飆升到80%

分析過程:通過上述方法進行線程棧定位,並進行內存堆分析,發現pathRaterLimiterConcurrentHashMap對象佔用大量堆空間,找到程序中對應的filter過濾器代碼如下

public HttpRequestMessage apply(HttpRequestMessage request) {
String requestPath = request.getPath();
if (pathRaterLimiterConcurrentHashMap.containsKey(requestPath)) {
if (!pathRaterLimiterConcurrentHashMap.get(requestPath).tryAcquire()) {
log.warn("too many request:"+requestPath+",time:"+System.currentTimeMillis());
SessionContext context = request.getContext();
if(requestPath!=null && requestPath.equals("/voting/selection")){
context.setEndpoint(VoteTimeOutEndpoint.class.getCanonicalName());
}
//context.setEndpoint(ManyRequestsEndpoint.class.getCanonicalName());
request.setPath("/404.html");
context.setRouteVIP("limit-api");
}
} else {
pathRaterLimiterConcurrentHashMap.put(requestPath, RateLimiter.create(limit));
pathRaterLimiterConcurrentHashMap.get(requestPath).tryAcquire();
}
return request;
}

分析發現當url不斷增加時,map的k-v會不斷增加,以至於最後頻繁觸發fullgc,導致cpu飆升。

解決方案:跑一個定時任務線程定期清理map中的對象,後採用LRU算法重寫一個maputil,定時清理過期的key值。

正則表達式案例

案例背景:前幾天線上一個項目監控信息突然報告異常,上到機器上後查看相關資源的使用情況,發現 CPU 利用率將近 100%。

分析過程:

通過 Java 自帶的線程 Dump 工具,我們導出了出問題的堆棧信息。我們可以看到所有的堆棧都指向了一個名為 validateUrl 的方法,這樣的報錯信息在堆棧中一共超過 100 處。通過排查代碼,我們知道這個方法的主要功能是校驗 URL 是否合法。

很奇怪,一個正則表達式怎麼會導致 CPU 利用率居高不下。為了弄清楚復現問題,我們將其中的關鍵代碼摘抄出來,做了個簡單的單元測試。

public static void main(String[] args) {
String badRegex = "^([hH][tT]{2}[pP]://|[hH][tT]{2}[pP][sS]://)" +
"(([A-Za-z0-9-~]+).)+([A-Za-z0-9-~\\\\/])+$";
String bugUrl = "http://www.fapiao.com/dddp-web/pdf/download?" +
"request=6e7JGxxxxx4ILd-kExxxxxxxqJ4-CHLmqVnenXC692m7" +
"4H38sdfdsazxcUmfcOH2fAfY1Vw__%5EDadIfJgiEf";
if (bugUrl.matches(badRegex)) {
System.out.println("match!!");
} else {
System.out.println("no match!!");
}
}

正則表達式分為三部分:

第一部分匹配 http 和 https 協議,第二部分匹配 www. 字符,第三部分匹配許多字符。我看著這個表達式發呆了許久,也沒發現沒有什麼大的問題。

其實這裡導致 CPU 使用率高的關鍵原因就是:Java 正則表達式使用的引擎實現是 NFA 自動機,這種正則表達式引擎在進行字符匹配時會發生回溯(backtracking)。而一旦發生回溯,那其消耗的時間就會變得很長,有可能是幾分鐘,也有可能是幾個小時,時間長短取決於回溯的次數和複雜度。

正則表達式是一個很方便的匹配符號,但要實現這麼複雜,功能如此強大的匹配語法,就必須要有一套算法來實現,而實現這套算法的東西就叫做正則表達式引擎。簡單地說,實現正則表達式引擎的有兩種方式:DFA 自動機(Deterministic Final Automata 確定型有窮自動機)和 NFA 自動機(Non deterministic Finite Automaton 不確定型有窮自動機)。

對於這兩種自動機,他們有各自的區別,這裡並不打算深入將它們的原理。簡單地說,DFA 自動機的時間複雜度是線性的,更加穩定,但是功能有限。而 NFA 的時間複雜度比較不穩定,有時候很好,有時候不怎麼好,好不好取決於你寫的正則表達式。

解決方案:

其實在正則表達式中有這麼三種模式:貪婪模式、懶惰模式、獨佔模式。在關於數量的匹配中,有 + ? * {min,max} 四種,如果只是單獨使用,那麼它們就是貪婪模式。

如果在他們之後加多一個 ? 符號,那麼原先的貪婪模式就會變成懶惰模式,即儘可能少地匹配。但是懶惰模式還是會發生回溯現象的。

如果在他們之後加多一個 + 符號,那麼原先的貪婪模式就會變成獨佔模式,即儘可能多地匹配,但是不回溯。

String goodRegex = "^([hH][tT]{2}[pP]://|[hH][tT]{2}[pP][sS]://)" +
"(([A-Za-z0-9-~]+).)++([A-Za-z0-9-~\\\\/])+$";

Excel導出案例

案例背景:京東某系統使用了poi-ooxml-3.5-final做excel導出功能。起初使用該版本的poi的HSSF配合多線程生成excel,沒有任何問題,後來改成了XSSF生成後上線,導出3w條數據時,cpu使用率達到了100%,內存達到了100%

由於cpu使用率打爆,內存打爆,整個伺服器處於拒絕服務狀態,而呈現到前端則是應用系統大部分卡死。於是業務方不斷反覆點擊導出按鈕,狀況不斷擴大到集群內其他機器上,導致集群出現雪崩現象。

分析過程

由於伺服器已經被打死,內存那麼高,根本無法dump線上堆內存,甚至連jstack查看線程棧都無法使用。因此嘗試在測試機復盤

可見eden空間的s0和s1已經無法交換了,eden空間已經完全打滿,old空間也一樣打滿,yong gc和full gc都非常頻繁,cpu自然使用率高了,不過不足以打滿整個cpu!現在目前定位到了fullgc沒有回收垃圾,那麼需要找到內存打滿和為啥沒回收的原因。要想找到內存打滿的原因肯定需要分析heap空間對象。

由於問題出現在導出報表,並且已知升級了版本並且改成了單線程導出就解決了,同時之前使用HSSF的時候並沒有出現問題,也證明了業務代碼沒有問題,問題出現在XSSF的版本和多線程上。所以本地可以模擬poi-ooxml-3.5-FINAL的XSSF進行大量數據的導出實驗,同時需要進行多線程導出。

在本地mock數據可以使用簡單的大量對象構成的結構進行導出,線上30個列導出,本地測試5個列,線上是本地的6倍,線上的每一行的數據量必然要比本地的數據量大很多。同時懷疑是poi-ooxml-3.5-FINAL內存洩露或內存管理出現的問題,那麼其實不需要4g內存,在2g的內存下壓榨到死看看heap中大量的對象是不是poi相關的就可以了。然後再升級下版本,繼續壓榨一下看看會不會壓死即可。

public static void main(String[] args) {
int size = 500000;
List<User> users = new ArrayList<>(size);
User user;
for (int i = 0; i < size; i++) {
user = new User();
user.setId(Integer.toUnsignedLong(i));
user.setAge(i + 10);
user.setName("user" + i);
user.setRemark(System.currentTimeMillis() + "");
user.setSex("男");
users.add(user);
}

new Thread(() -{
String[] columnName = {"用戶id", "姓名", "年齡", "性別", "備註"};
Object[][] data = new Object[size][5];
int index = 0;
for (User u : users) {
data[index][0] = u.getId();
data[index][1] = u.getName();
data[index][2] = u.getAge();
data[index][3] = u.getSex();
data[index][4] = u.getRemark();
index++;
}
XSSFWorkbook xssfWorkbook = generateExcel("test", "test", columnName, data);
}).start();
try {
Thread.currentThread().join();//等待子線程結束
} catch (InterruptedException e) {
e.printStackTrace();
}
}

模擬現象與線上情況類似,大量cpu佔用在XSSFCell.setCellValue中,生成excel generateExcel就佔據了所有的cpu,堆信息全是POI對象

這裡還需要注意的是,需要驗證poi-ooxml-3.5-FINAL在多線程情況下是否會出現這個問題,驗證很簡單,把new Thread去掉,直接在主線程導出。這裡直接說明實驗結果,new Thread去了依然內存爆滿!

解決方案

查看poi官網的change log http://poi.apache.org/changes.html ,既然3.5-FINAL的XSSF有問題,向上查找3.5-FINAL之後的XSSF相關字樣的信息,會發現在3.6中memory usage optimization in xssf - avoid creating parentless xml beans,xxsf進行中做了內存優化 - 避免了創建無父類的xml bean對象

所以得出結論,升級poi-oxxml版本到3.6或者更高版本!


相關焦點

  • 什麼會導致Java應用程式的CPU使用率飆升?
    問題無限循環的while會導致CPU使用率飆升嗎?經常使用Young GC會導致CPU佔用率飆升嗎?具有大量線程的應用程式的CPU使用率是否較高?CPU使用率高的應用程式的線程數是多少?處於BLOCKED狀態的線程會導致CPU使用率飆升嗎?分時作業系統中的CPU是消耗us還是sy?
  • CPU使用率飆升至100%?按這3步走,找出罪該禍首!
    小夥伴們,如果你們在使用電腦的時候,電腦突然變得異常卡頓、死機、加載很慢,那趕緊去看看電腦的cpu使用率!談到cpu,我們都知道它是電腦的運算核心,也是電腦的控制核心,是每臺電腦中的最重要的一個硬體。CPU使用率的真正含義那麼cpu使用率的真正含義是什麼呢?
  • cpu使用率超過100%排查思路
    在日常運維過程中,進程碰到的問題,cpu使用率超過100%,那碰到這個問題時,需要怎麼去定位,到底什麼原因導致cpu使用率超標,首先需要定位看看是什麼進程消耗掉了cpu資源。第一步可以使用ps命令查看一下ps aux|sort -n -k4|tail -20上述命令可以查看消耗cpu資源最多的20個進程,不過是逆序的。
  • cpu使用率過高的原因及解決方法【圖文教程】
    要解決CPU使用率過高,首先我們要明白CPU過高是什麼原因造成的,我們主要從軟體與硬體入手:  ⒈)軟體方面導致的CPU對於如今入門雙核處理器儘管滿足基本上網與辦公流暢,但運行大型應用也同樣會存在CPU使用率高的問題,因此在DIY裝機中我們一定要了解電腦的用途與需求,選擇合適的電腦配置。  最後我們再來重點與大家介紹下CPU使用率過高的解決辦法。
  • 電腦CPU使用率高的解決對策
    下面就來跟大家講解電腦cpu使用率高的處理技巧。一旦cpu的佔用率過高,電腦的運行速度就會明顯地慢了下來,若佔用率達到了最大值100%,那麼就可能導致操作極度緩慢或死機等情況。當我們遇到電腦cpu佔用率過高的情況時,該如何解決呢?下面就來跟大家分享電腦cpu使用率高的解決對策。
  • 如何能讓CPU的使用率達到100%??
    身為一名合格的運維攻城獅,看到CPU使用率100%肯定多少有些緊張,因為我們的使命就是要將CPU使用率給降下來。
  • 絕地求生cpu使用率100怎麼辦
    18183首頁 絕地求生 絕地求生cpu使用率100怎麼辦 絕地求生cpu使用率100怎麼辦 來源:網絡
  • cpu使用率忽高忽低怎麼辦
    作業系統:win10 1909 64位企業版使用計算機時,我們經常會遇到意外或意外的問題,因此我們會遇到如果cpu使用量出現波動怎麼辦呢?下面就來看看遇到電腦如果cpu使用量出現波動怎麼辦。2.我看到計算機的CPU使用率高,低或高。在這種情況下,通常會打開某些佔用CPU的軟體,並且通常無法確定哪個軟體佔用了CPU。這並不意味著軟體越大,佔用的CPU越多。 。3.單擊性能項目的資源監視器。4.在資源監視器選項卡下,您可以直觀地看到哪個軟體佔用最多的CPU。
  • CPU使用率高怎麼辦 CPU使用率過高的解決辦法
    那麼針對CPU使用率高怎麼辦呢?網上關於這個話題討論很多,其實都是從兩個方面去考慮,一個是軟體方面,另外一個則是硬體方面,其中硬體方面其決定性因素,下面我們一起來詳細與大家分析下。CPU使用率高怎麼辦要解決CPU使用率過高,首先我們要明白CPU過高是什麼原因造成的,我們主要從軟體與硬體入手:⒈)軟體方面導致的CPU
  • CPU使用率飆升,或直接損壞SSD,勿升級
    據一位用戶在Reddit帖子中指出:「高CPU和磁碟使用率,它發作的時候我甚至無法正常觀看流媒體和視頻。無奈之下只有卸載了那個程序。」後經檢查發現,該問題很有可能是因為DSAService.exe更新引起的,它會造成50-100%的CPU峰值,以及顯卡玩遊戲時的FPS下降。
  • 玩遊戲cpu使用率100%怎麼辦
    CPU又稱中央處理器,是一臺計算機的控制中心,有時候我們使用電腦玩遊戲的時候可能會出現CPU使用率為100%的現象產生,CPU使用率長期保持在100%的情況下容易導致系統出現崩潰。下面小編為大家分享下碰到此種情況的解決辦法,希望對大家有所幫助。
  • cpu過高電腦反應慢,cpu使用率100%怎麼辦
    其實CPU過高無非就那幾種原因,電腦打開文件及應用程式過多、電腦中毒等等,但因為不少人都對這一方面缺乏,所以面對著CPU過高也無從下手,對著網上一些不靠譜的教程照著弄一下也無濟於事,下面我來說下下面我來說下cpu過高電腦反應慢,cpu使用率100%怎麼辦。
  • 電腦CPU使用率「高」的朋友們!您可得要注意下面了!
    對於很多使用電腦的朋友來說他們還是不知道怎麼去解決這些問題的,接下來小編給大家科普一下關於CPU的知識,以及解決方案。CPU佔用率過高一般都和電腦的軟體設置存儲以及硬體高低有關。接下來小編把降低CPU也分為軟體與硬體兩個部分展開來說。
  • 電腦開機後CPU使用率直接100%,你的電腦還能「動」嗎?
    現在我為大家做專業技術解答,我們都知道,CPU不但是電腦的運算核心也是電腦的控制核心,一臺電腦中最重要的一個硬體就是CPU硬體,可以說CPU硬體決定了電腦的綜合性能。CPU使用率高而導致電腦運行不流暢的朋友應該對CPU的重要性深有體會了,那電腦為何開機後CPU佔用率直接飆升到100%了呢?
  • 電腦開機後CPU使用率直接100%,你的電腦還能「動」嗎?
    現在我為大家做專業技術解答,我們都知道,CPU不但是電腦的運算核心也是電腦的控制核心,一臺電腦中最重要的一個硬體就是CPU硬體,可以說CPU硬體決定了電腦的綜合性能。CPU使用率高而導致電腦運行不流暢的朋友應該對CPU的重要性深有體會了,那電腦為何開機後CPU佔用率直接飆升到100%了呢?
  • CPU超頻小知識:CPU什麼情況下需要超頻?CPU超頻需要什麼條件?
    那麼CPU什麼情況下需要超頻?CPU超頻需要什麼條件?下面裝機之家曉龍就來幫大家科普一下。CPU超頻小知識一、什麼是CPU頻率嗎?CPU頻率其實就是指CPU在一秒內發生脈衝的次數,單位是赫茲,同一款CPU在一秒內發生脈衝的次數越多,就說明它的運行速度越快。二、CPU超頻有什麼用?
  • CPU使用率過高的解決方法總結
    網上關於這個話題討論很多,其實都是從兩個方面去考慮,一個是軟體方面,另外一個則是硬體方面,其中硬體方面其決定性因素,下面我們一起來詳細與大家分析下。CPU過高是什麼原因造成的,我們主要從軟體與硬體入手:⒈)軟體方面導致的CPU使用率高這方面主要涉及到的是系統問題,比如系統過於臃腫,開啟過多程序以及電腦中病毒木馬等等都會產生CPU使用率過高,而導致電腦速度慢。
  • 如何正確理解 CPU 使用率和平均負載的關係?看完你就知道了
    當 CPU 過於繁忙,就像「人腦」並發處理過多的事情,會降低做事的效率,嚴重時甚至會導致崩潰「宕機」。因此,理解 CPU 的工作原理,合理控制負載,是保障系統穩定持續運行的重要手段。CPU 的物理核與邏輯核一臺機器可能包含多塊 CPU 晶片,多個 CPU 之間通過系統總線通信。
  • cpu 使用率過高和 jvm old 佔用過高排查過程
    cpu佔用過高和jvm old佔用過高,這個時候趕緊去排查原因,下面記錄了我的排查過程,可能裡面還有不正確的地方,歡迎各位大佬指正,也歡迎大家關於類似的案例一起交流,下面就看我關於這次排查的過程把報警cpu使用率過高報警,接近100%後續又來了jvm old過高報警排查過程首先打開監控平臺看報警節點的cpu使用情況登錄伺服器找到佔用 c
  • 90%的CPU使用率意味著什麼?
    CPU使用率(CPU utilization)直觀顯示了運行程序佔用的CPU資源,使用率越高,說明你的機器在這個時間上運行了很多程序,一般情況下