當前位置:
首頁 > 最新 > 全攻略!JAVA應用性能問題定位與解決

全攻略!JAVA應用性能問題定位與解決

任何產品,

無論什麼用戶,用途,定位,

都有一個共同的目標:

好用。

而對於軟體來說,所謂的好用,

就是儘可能地提高產品性能,

使產品能夠及時完成所有功能的運行。

為了達到提高性能的目標,必須做到

吞吐率高,

響應速度快,

以及性能穩定

這三方面。

1

常見問題

在Java應用的運行過程中,有三個性能問題總是會影響到應用的正常運行,甚至導致應用不可用:

CPU高使用率

堆內存溢出(OOM)

TPS低

針對這三個問題,我們一一給出解決方案:

問題1:

CPU高使用率

問題描述

通常可以觀察到一個或者多個java VM進程,這些進程佔用了過高操作系統的CPU資源。「過高」的定義需要建立一個閾值,比如達到了系統CPU使用率峰值的2倍。

這個問題對運維人員或使用者的感知也許沒有那麼強,因為並不一定會導致服務不可用,所以可能只是重啟了事。

但是相信我,問題並不會就此被解決。我們需要做的,是在服務重啟之前,抓取有效信息並分析。

定位與解決

一個典型的Java VM進程包含若干個線程,有些在工作,有些在等待。

在單個Java程序中,線程的數量可能非常少。而對於大量處理並發事務的企業級java EE平台,線程的數量會變得非常多。所以弄清楚當前Java VM進程中的線程活動情況,對分析此問題至關重要。

下面我們通過生成ThreadDump(線程快照),並結合操作系統定位具體的佔用CPU資源高的線程。

方法介紹(操作系統以linux為例):

Step1 : 找到進程

通過top命令,找到佔用cpu高的java pid

Step2 : 找到線程

通過top -Hp [pid],找到佔用cpu高的java 線程

Step3 : 生成java threadDump

使用jdk自帶的jstack工具,執行,將線程快照信息重定向至文本

Step4 : 定位線程

將Step2中得到的佔用cpu高的線程id,轉換成16進位,在中搜索native線程id一致的線程。

Step5 : 線程執行分析

通過中記錄的當前線程運行代碼堆棧, 可以很明確的定位到出現問題的java代碼,之後分析代碼找到具體問題解決。

一般情況下,如果不是因為在進行複雜計算,那麼就是有大量循環甚至死循環。所以,優化代碼吧朋友!

問題2:

堆內存溢出

問題描述

在Java 程序中,常見的內存溢出類型是heap space(堆內存)溢出。一旦出現這個問題,在應用伺服器日誌中會拋出,GC日誌中也有明顯記錄。

造成堆內存溢出的原因主要有3個:

JVM堆內存配置過小

JVM在啟動時,可以指定堆內存大小,如果配置過小,同時應用程序申請較大的堆空間,就會發生內存溢出錯誤。

峰值大對象

一個Java應用被設計來處理一定數量的訪問量或者數據,當這個數量猛然升高時,java應用需要申請超過預期的堆內存空間,就會導致內存溢出。

內存泄露

由於某些編程錯誤,導致Java應用不斷消耗堆內存。每當這些會導致泄露的功能被使用時,都會殘留一些對象在堆內存空間中,並且不會被GC回收,長期下去,這些對象會佔滿堆內存空間,導致內存溢出錯誤。

定位與解決

分析堆內存溢出問題的最好辦法,就是了解當前堆內存空間中,都有哪些對象。最好是在發生OutOfMemoryError時,能自動生成一個堆內存快照。

是的,Java已經具備了這樣的功能,我們可以通過指定JVM參數來啟用此功能:

這樣的話,我們就可以很容易的分析出產生問題時,究竟是哪些對象佔用了堆內存空間。推薦使用Memory Analyzer Tool,打開生成的快照文件。

單憑堆內存中的Java對象,還不足以定位具體的問題代碼位置,因為可能有很多場景均會生成同樣類型的Java對象。

那麼可以在發生堆存溢出時,也同時生成線程堆棧,同時結合java線程和內存中java對象,可以分析出是哪一個線程代碼在執行時導致了此問題。

解決思路舉例:

調大jvm堆內存空間

限制從資料庫查詢返回的結果集大小

根據業務情況限制查詢的條件,如時間間隔在一個月以內

限制上傳伺服器的文件大小

合理使用JVM緩存,避免緩存大對象

問題3:

TPS低

問題描述

大家可能都有這樣的經歷:在線上生產環境,忽然訪問請求堆積,頻頻超時報警;或者是在做性能壓力測試時,TPS遇到瓶頸,難以提升。

不論哪種情況,都意味著系統存在性能問題,需要分析解決。

定位與解決

TPS低往往是一系列性能問題交疊產生的,較為複雜,在正常的請求條件下也不一定能暴露問題,需要發起壓力測試來幫助我們定位與解決。

壓力測試過程:

一個獨立的性能測試環境是必須的,且儘可能的模擬真實生產環境:

發起性能壓力測試,建立當前環境下的第一代性能基線;

分析性能基線,測算並找到性能瓶頸;

優化後再次發起性能壓力測試,建立第二代性能基線;

重複以上,直到認為TPS及各項指標達標。

問題的定位與解決,是基於各類數據信息的採集與分析,那我們來數一數,有幾類信息是需要重點關注的:

熱點方法

熱點方法反映了當前請求處理邏輯中,哪些業務方法耗時較長,往往熱點方法就是導致TPS低的禍首,可以通過jdk提供的visualvm或者專業的應用監控工具檢測發現。

GC日誌

GC日誌詳細記錄了Java應用程序中,GC活動情況,包括GC次數、GC類別、GC暫停時間和各內存區域大小等信息。通過分析GC日誌,可以很容易的發現Java應用程序是否存在內存泄露和長GC暫停時間。

Java線程堆棧

線程堆棧,記錄了生成瞬時所有Java線程的活動情況,包括線程運行狀態、線程當前執行方法等信息。通過分析線程堆棧,可以發現java線程間是否存在死鎖和阻塞。

2

優化思路

基於以上信息分析,可以找到性能瓶頸所在,這個時候就需要我們對應用邏輯代碼做一定的優化,可以說,絕大部分的性能問題,都是由於應用端編程導致的。

思路一:

緩存

緩存是我們常用的優化方法,可以有效的減少系統或模塊之間的交互,降低請求耗時。

主要有2種緩存處理方式:

1. 分布式數據緩存

各個應用伺服器共享的數據資源;

數據量大;

一定頻率的數據失效或刷新;

2. JVM本地緩存

訪問頻率高;

數據變動頻率不高或者幾乎無變化;

數據量小;

讀寫比高;

思路2:

非同步

這裡指的「非同步」,是將一件事情,拆分成兩個或者更多的步驟完成,以提高吞吐率。我們可以針對一個業務場景,抽象出生產者和消費者,並解耦他們,提煉出非同步階段。

常用實現方式:

自定義事件監聽EventListener

定時任務

消息隊列

思路3:

拆分

一個過於龐雜的業務集合或者一個數據量過大的對象,對java應用來說,都是非常不友好的,因為會佔用較多的系統資源,在並發情況下,處理能力偏低。

如果有這樣的問題,我們可以做如下處理:

1. 場景拆分

將單個複雜業務場景拆分成非同步處理的多個階段;

將耗時較長的API拆分成多個消耗較小的簡單API;

將cost較高的複雜sql拆分成多個小sql。

2. 數據拆分

大數據量下,按照一定規則將數據拆分到多個線程處理;

處理大量數據時,可以循環多次取少量數據,避免一次性取出過多數據而導致OOM。

3

分析工具推薦

方式1:

GC日誌分析

工具名稱:IBM Pattern Modeling and Analysis Tool for Java Garbage Collector (PMAT)

這是IBM出品的一款解析GC日誌工具,分析java堆內存使用情況,並能提供關鍵配置建議。

Link:https://www.ibm.com/developerworks/community/groups/service/html/communityview?communityUuid=22d56091-3a7b-4497-b36e-634b51838e11&open

方式2:

ThreadDump分析:

工具名稱:IBM Thread and Monitor Dump Analyzer for Java

IBM出品的一款java線程堆棧分析工具,支持IBM JDK和Oracle JDK,可以快速分析並提示線程dump信息。

各線程狀態與佔比(deadLock、waiting、blocked等)。

線程當前執行方法及佔比。

同時打開多個線程dump文件並對比。

Link:

https://www.ibm.com/developerworks/community/groups/service/html/communityview?communityUuid=2245aa39-fa5c-4475-b891-14c205f7333c

方式3:

HeapDump分析

工具名稱:Memory Analyzer Tool

MAT(Memory Analyzer Tool),一個基於Eclipse的內存分析工具,是一個快速、功能豐富的JAVA heap分析工具,它可以幫助我們查找內存泄漏和減少內存消耗。

內存對象分布

內存對象大小

自動報告內存泄露

Link:

http://www.eclipse.org/mat/

方式4:

實時程序監控分析

名稱:VisualVM

VisualVM 是一款免費的集成了多個JDK 命令行工具的可視化工具,可以在jdk安裝目錄找到這款工具,它易於使用、功能強大且插件眾多,是java應用性能監控常用的工具。

4

結語

相信通過本文,可以為大家提供一些解決java程序常見性能問題的思路,但是事前設計依然大於事後優化,我們應該將這些優化思想帶入到設計階段,這才是最重要的。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 公眾號 的精彩文章:

你知道大蒜怎麼保存么?
皰疹病毒性角膜炎的根治術醫生手記
細膩的喜歡,毛毯般的厚重感,曬過太陽熟悉的安全感
《方言說蘇州》(2)
一路走來,真誠感謝素不相識的你們!

TAG:公眾號 |

您可能感興趣

SteamVR推出解析度調諧器,自適應最佳解析度,充分利用GPU性能
SteamVR推出解析度調諧器,自適應最佳解析度、超級採樣,充分利用GPU性能
UWA性能測評全面支持各種Lua!
如何快速定位MySQL性能問題
絕地求生:為何職業賽場AKM登場率如此之高?AKM性能全方位解析
身為QA,你是否也了解SQL性能優化?
當AMG已經無法滿足你對高性能的需求,你可能會選擇TA!
什麼是MAP?理解目標檢測模型中的性能評估
提升Windows系統性能全面優化詳解
印度裝備的英薩斯INSAS步槍性能具體怎麼樣?性能奇差,無彈可用
NVIDIA控制面板3D設置切換高性能顯卡出現拒絕訪問對話框的解決方法
未來iPhone自行決定是否將性能變慢?避免無預警關機
深鑒科技正式入局自動駕駛賽道 高性能ADAS視覺解決方案落地新節點
Cobra吳忌寒推特論戰引網友發文站隊:PoW是最安全的共識機制,要從機制上解決比特幣的性能問題
vivo NEX詳細評測:AI加持的真全面屏性能旗艦
如何在閉環控制應用中提高系統性能?
對標EOS,全球首個基於DAG技術並支持智能合約的高性能公鏈Fantom完成融資
「二維垂直」策略全方位提升MOF在超級電容器的性能
與iMac做競爭對手:Wbin AIO曲面一體機顏值高性能好
如何通過軟引用和弱引用提升JVM內存使用性能