日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

深入理解JVM性能调优

發布時間:2023/12/2 综合教程 26 生活家
生活随笔 收集整理的這篇文章主要介紹了 深入理解JVM性能调优 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

深入理解JVM性能調優

您的評價: ????? ?收藏該經驗????

width="728" height="90" frameborder="0" marginwidth="0" marginheight="0" vspace="0" hspace="0" allowtransparency="true" scrolling="no" allowfullscreen="true" id="aswift_0" name="aswift_0" style="padding: 0px; margin: 0px; left: 0px; position: absolute; top: 0px;">

??? 在上文中我們分析了很多性能監控工具,介紹這些工具的目的只有一個,那就是找出對應的性能瓶頸。盲目的性能調優是沒有效果的,只有充分知道了哪里出了問題,針對性的結果才是立竿見影的。解決了主要的性能問題,那些次要的性能問題也就不足為慮了!

我們知道,性能問題無非就這么幾種:CPU、內存、磁盤IO、網絡。那我們來逐一介紹以下相關的現象和一些可能出現的問題。

一、CPU過高。

查看CPU最簡單的我們使用任務管理器查看,如下圖所示,windows下使用任務管理器查看,Linux下使用top查看。

一般我們的服務器都采用Linux,因此我們重點關注一下Linux(注:windows模式下相信大家已經很熟悉了,并且前面我們已經提到,使用資源監視器可以很清楚的看到系統的各項參數,在這里我就不多做介紹了)

在top視圖下,對于多核的CPU,顯示的CPU資源有可能超過100%,因為這里顯示的是所有CPU占用百分百的總和,如果你需要看單個CPU的占用情況,直接按鍵1就可以看到。如下圖所示,我的一臺測試機為8核16GB內存。

?在

top?視圖下,按鍵?shift+h?后,會顯示各個線程的?CPU?資源消耗情況,如下圖所示:

?我們也可以通過

sysstat?工具集的?pidstat?來查看

注:sysstat下載地址:http://sebastien.godard.pagesperso-orange.fr/download.html

安裝方法:

1、chmod +x configure

2、./configure

3、make

4、make install

如輸入pidstat 1 2就會隔一秒在控制臺輸出一次當然CPU的情況,共輸出2次

?除了

top?、?pidstat?以外,?vmstat?也可以進行采樣分析

?相關

top?、?pidstat?、?mstat?的用法大家可以去網上查找。

下面我們主要來介紹以下當出現CPU過高的時候,或者CPU不正常的時候,我們該如何去處理?

CPU消耗過高主要分為用戶進程占用CPU過高和內核進程占用CPU過高(在Linux下top視圖下us指的是用戶進程,而sy是指內核進程),我們來看一個案例:

?程序運行前,系統運行平穩,其中藍色的線表示總的

CPU?利用率,而紅色的線條表示內核使用率。部署?war?測試程序,運行如下圖所示:

?對于一個

web?程序,還沒有任何請求就占用這么多?CPU?資源,顯然是不正常的。并且我們看到,不是系統內核占用的大量?CPU?,而是系統進程,那是哪一個進程的呢?我們來看一下。

?很明顯是我們的

java?進程,那是那個地方導致的呢?這就需要用到我們之前提到的性能監控工具。在此我們使用可視化監控工具?VisualVM。

?首先我們排除了是

GC?過于頻繁而導致大?CPU?過高,因為很明顯監控視圖上沒有?GC?的活動。然后我們打開?profilter?去查看以下,是那個線程導致了?CPU?的過高?

?前面一些線程都是容器使用的,而下面一個線程也一直在執行,那是什么地方調用的呢?查找代碼中使用

ThredPoolExecutor?的地方。終于發現以下代碼。

????private?BlockingQueuequeue;

????private?Executor?executor;

//……

public?void?run() {

????????while(true){

???????????try?{

??????????????SendMsg sendMsg =?queue.poll();//從隊列中取出

??????????????if(null?!= sendMsg) {

??????????????????sendForQueue(sendMsg);

??????????????}

???????????}?catch?(Exception e) {

??????????????e.printStackTrace();

???????????}

???????}

????}

問題很顯然了,我們看一下對應BlockingQueue的poll方法的API文檔。

?不難理解了,雖然使用了阻塞的隊列,但是使用了非阻塞的取法,當數據為空時直接返回

null?,那這個語句就等價于下面的語句。

@Override

????public?void?run() {

???????while(true){

??????????

???????}

????}

相當于死循環么,很顯然是非常耗費CPU資源的,并且我們還可以發現這樣的死循環是耗費的單顆CPU資源,因此可以解釋上圖為啥有一顆CPU占用特別高。我們來看一下部署在Linux下的top視圖。

?猛一看,不是很高么?我們按鍵

1?來看每個單獨?CPU?的情況!

?這下看的很清楚了吧!明顯一顆

CPU?被跑滿了。(因為一個單獨的死循環只能用到一顆?CPU?,都是單線程運行的)。

問題找到,馬上修復代碼為阻塞時存取,如下所示:

@Override

????public?void?run() {

???????while(true){

???????????try?{

??????????????SendMsg sendMsg =?queue.take();//從隊列中取出

??????????????sendForQueue(sendMsg);

???????????}?catch?(Exception e) {

??????????????e.printStackTrace();

???????????}

???????}

????}

?再來監控

CPU?的變換,我們可以看到,基本上不消耗?CPU?資源(是我沒做任何的訪問哦,有用戶建立線程就會消耗)。

?再來看

java?進程的消耗,基本上不消耗?CPU?資源

?

再來看VisualVM的監控,我們就可以看到基本上都是容器的一些線程了

?以上示例展示了

CPU?消耗過高情況下用戶線程占用特別高的情況。也就是?Linux?下?top?視圖中?us?比較高的情況。發生這種情況的原因主要有以下幾種:程序不停的在執行無阻塞的循環、正則或者純粹的數學運算、?GC?特別頻繁。

CPU過高還有一種情況是內核占用CPU很高。我們來看另外一個示例。

package?com.yhj.jvm.monitor.cpu.sy;

?

import?java.util.Random;

import?java.util.concurrent.ExecutorService;

import?java.util.concurrent.Executors;

?

/**

?*?@Described:系統內核占用CPU過高測試用例

?*?@author?YHJ create at 2012-3-28?下午05:27:33

?*?@FileNmae?com.yhj.jvm.monitor.cpu.sy.SY_Hign_TestCase.java

?*/

public?class?SY_Hign_TestCase {

???

????private?final?static?int?LOCK_COUNT?= 1000;

?

????//默認初始化LOCK_COUNT個鎖對象

????private?Object []?locks?=?new?Object[LOCK_COUNT];

?

????private?Random?random?=?new?Random();

?

????//構造時初始化對應的鎖對象

????public?SY_Hign_TestCase() {

???????for(int?i=0;i<LOCK_COUNT;++i)

???????????locks[i]=new?Object();

????}

?

?

?

????abstract?class?Task?implements?Runnable{

?

???????protected?Object?lock;

?

???????public?Task(int?index) {

???????????this.lock=?locks[index];

???????}

???????@Override

???????public?void?run() {

???????????while(true){??//循環執行自己要做的事情

??????????????doSth();

???????????}

???????}

???????//做類自己要做的事情

???????public?abstract?void?doSth();

????}

?

????//任務A?休眠自己的鎖

????class?TaskA?extends?Task{

?

???????public?TaskA(int?index) {

???????????super(index);

???????}

?

???????@Override

???????public?void?doSth() {

???????????synchronized?(lock) {

??????????????try?{

??????????????????lock.wait(random.nextInt(10));

??????????????}?catch?(InterruptedException e) {

??????????????????e.printStackTrace();

??????????????}

???????????}

???????}

?

????}

?

????//任務B?喚醒所有鎖

????class?TaskB?extends?Task{

??????

???????public?TaskB(int?index) {

???????????super(index);

????????}

?

???????@Override

???????public?void?doSth() {

???????????try?{

??????????????synchronized?(lock) {

??????????????????lock.notifyAll();

??????????????????Thread.sleep(random.nextInt(10));

??????????????}

???????????}?catch?(InterruptedException e) {

??????????????e.printStackTrace();

???????????}

???????}

?

????}

????//啟動函數

????public?void?start(){

???????ExecutorService service = Executors.newCachedThreadPool();

???????for(int?i=0;i<LOCK_COUNT;++i){

???????????service.execute(new?TaskA(i));

???????????service.execute(new?TaskB(i));

???????}

????}

????//主函數入口

????public?static?void?main(String[] args) {

???????new?SY_Hign_TestCase().start();

????}

?

}

代碼很簡單,就是創建了2000個線程,讓一定的線程去等待,另外一個線程去釋放這些資源,這樣就會有大量的線程切換,我們來看下效果。

?很明顯,

CPU?的內核占用率很高,我們拿具體的資源監視器看一下:

?很明顯可以看出有很多線程切換占用了大量的

CPU?資源。

同樣的程序部署在Linux下,top視圖如下圖所示:

?展開對應的

CPU?資源,我們可以清晰的看到如下情形:

?大家可以看到有大量的

sy?內核占用,但是也有不少的?us?,?us?是因為我們啟用了大量的循環,而?sy?是因為大量線程切換導致的。

我們也可以使用vmstat來查看,如下圖所示:

?二、文件

IO?消耗過大,磁盤隊列高。

在windows環境下,我們可以使用資源監視器查看對應的IO消耗,如下圖所示:

?這里不但可以看到當前磁盤的負載信息,隊列詳情,還能看到每個單獨的進程的資源消耗情況。

Linux下主要使用pidstat、iostat等進行分析。如下圖所示

Pidstat –d –t –p [pid] {time} {count}

如:pidstat -d -t -p 18720 1 1

Iostat

?

Iostat –x xvda 1 10做定時采樣

?廢話不多說,直接來示例,上干貨!

package?com.yhj.jvm.monitor.io;

?

import?java.io.BufferedWriter;

import?java.io.FileWriter;

import?java.io.IOException;

import?java.util.concurrent.ExecutorService;

import?java.util.concurrent.Executors;

?

/**

?*?@Described:IO測試用例

?*?@author?YHJ create at 2012-3-29?上午09:56:06

?*?@FileNmae?com.yhj.jvm.monitor.io.IO_TestCase.java

?*/

public?class?IO_TestCase {

???

????private?String?fileNmae?=?"monitor.log";

???

????private?String?context?;

???

????//?和CPU處理器個數相同,既充分利用CPU資源,又導致線程頻繁切換

????private?final?static?int?THRED_COUNT?= Runtime.getRuntime().availableProcessors();

???

????public?IO_TestCase() {//加長寫文件的內容,拉長每次寫入的時間

???????StringBuilder sb =?new?StringBuilder();

???????for(int?i=0;i<1000;++i){

???????????sb.append("context index :")

???????????.append(i)

???????????.append("\n");

???????????this.context=?new?String(sb);

???????}

????}

????//寫文件任務

????class?Task?implements?Runnable{

?

???????@Override

???????public?void?run() {

???????????while(true){

??????????????BufferedWriter writer =?null;

??????????????try?{

??????????????????writer =?new?BufferedWriter(new?FileWriter(fileNmae,true));//追加模式

??????????????????writer.write(context);

??????????????}?catch?(Exception e) {

??????????????????e.printStackTrace();

??????????????}finally{

??????????????????try?{

?????????????????????writer.close();

??????????????????}?catch?(IOException e) {

?????????????????????e.printStackTrace();

??????????????????}

??????????????}

???????????}

??????????

???????}

????}

????//啟動函數

????public?void?start(){

???????ExecutorService service = Executors.newCachedThreadPool();

???????for(int?i=0;i<THRED_COUNT;++i)

???????????service.execute(new?Task());

????}

????//主函數入口

????public?static?void?main(String[] args) {

???????new?IO_TestCase().start();

????}

?

}

這段示例很簡單,通過創建一個和CPU個數相同的線程池,然后開啟這么多線程一起讀寫同一個文件,這樣就會因IO資源的競爭而導致IO的隊列很高,如下圖所示:

?關掉之后馬上就下來了

?我們把這個部署到

Linux?上觀看。

?這里的

%idle?指的是系統沒有完成寫入的數量占用?IO?總量的百分百,為什么這么高我們的系統還能承受?因為我這臺機器的內存為16GB?的,我們來查看以下?top?視圖就可以清晰的看到。

?占用了大量的內存資源。

三、內存消耗

對于JVM的內存模型大家已經很清楚了,前面我們講了JVM的性能監控工具。對于Java應用來說,出現問題主要消耗在于JVM的內存上,而JVM的內存,JDK已經給我們提供了很多的工具。在實際的生成環境,大部分應用會將-Xms和-Xmx設置為相同的,避免運行期間不斷開辟內存。

對于內存消耗,還有一部分是直接物理內存的,不在堆空間,前面我們也寫過對應的示例。之前一個系統就是因為有大量的NIO操作,而NIO是使用物理內存的,并且開辟的物理內存是在觸發FULL GC的時候才進行回收的,但是當時的機器總內存為16GB?給堆的內存是14GB Edon為1.5GB,也就是實際剩下給物理呢哦村的只有0.5GB,最終導致總是發生內存溢出,但監控堆、棧的內存消耗都不大。在這里我就不多寫了!

四、網絡消耗過大

Windows下使用本地網絡視圖可以監控當前的網絡流量大小

?更詳細的資料可以打開資源監視器,如下圖所示

?Linux

平臺可以使用以下?sar?命令查看

sar -n DEV 1 2

?字段說明:

rxpck/s:每秒鐘接收的數據包

txpck/s:每秒鐘發送的數據包

rxbyt/s:每秒鐘接收的字節數

txbyt/s:每秒鐘發送的字節數

rxcmp/s:每秒鐘接收的壓縮數據包

txcmp/s:每秒鐘發送的壓縮數據包

rxmcst/s:每秒鐘接收的多播數據包

Java程序一般不會出現網絡IO導致問題,因此在這里也不過的的闡述。

五、程序執行緩慢

當CPU、內存、磁盤、網絡都不高,程序還是執行緩慢的話,可能引發的原因大致有以下幾種:

1程序鎖競爭過于激烈,比如你只有2顆CPU,但是你啟用了200個線程,就會導致大量的線程等待和切換,而這不會導致CPU很高,但是很多線程等待意味著你的程序運行很慢。

2未充分利用硬件資源。比如你的機器是16個核心的,但是你的程序是單線程運行的,即使你的程序優化的很好,當需要處理的資源比較多的時候,程序還會很慢,因此現在都在提倡分布式,通過大量廉價的PC機來提升程序的執行速度!

3其他服務器反應緩慢,如數據庫、緩存等。當大量做了分布式,程序CPU負載都很低,但是提交給數據庫的sql無法很快執行,也會特別慢。

總結一下,當出現性能問題的時候我們該怎么做?

一、CPU過高

1、??us過高

使用監控工具快讀定位哪里有死循環,大計算,對于死循環通過阻塞式隊列解決,對于大計算,建議分配單獨的機器做后臺計算,盡量不要影響用戶交互,如果一定要的話(如框計算、云計算),只能通過大量分布式來實現

2、??sy過高

最有效的方法就是減少進程,不是進程越多效率越高,一般來說線程數和CPU的核心數相同,這樣既不會造成線程切換,又不會浪費CPU資源

二、內存消耗過高

1、??及時釋放不必要的對象

2、??使用對象緩存池緩沖

3、??采用合理的緩存失效算法(還記得我們之前提到的弱引用、幽靈引用么?)

三、磁盤IO過高

1、??異步讀寫文件

2、??批量讀寫文件

3、??使用緩存技術

4、??采用合理的文件讀寫規則

四、網絡

1、增加寬帶流量

五、資源消耗不多但程序運行緩慢

1、使用并發包,減少鎖競爭

2、對于必須單線程執行的使用隊列處理

3、大量分布式處理

六、未充分利用硬件資源

1、??修改程序代碼,使用多線程處理

2、??修正外部資源瓶頸,做業務拆分

3、??使用緩存

轉自:http://yhjhappy234.blog.163.com/blog/static/3163283220122298232721/?suggestedreading&wumii

width="728" height="90" frameborder="0" marginwidth="0" marginheight="0" vspace="0" hspace="0" allowtransparency="true" scrolling="no" allowfullscreen="true" id="aswift_1" name="aswift_1" style="padding: 0px; margin: 0px; left: 0px; position: absolute; top: 0px;">

? 相關文檔? — 更多

  • 構建高性能的大型分布式Java應用.pdf
  • Twitter的JVM性能調優經驗分享.pdf
  • 深入理解JVM.docx
  • JVM 調優基礎.pdf
  • 基于JVM的異常診斷和性能調優.docx
  • Twitter的JVM性能調優經驗分享.pdf
  • Inside in JVM (深入理解java虛擬機英文).chm
  • 分布式Java應用基礎與實踐 第3章 深入理解JVM.pdf
  • 深入理解 Java 虛擬機 (JVM 高級特性與最佳實踐).pdf
  • JVM基礎調優實踐.pptx
  • JVM、GC詳解及調優.pdf
  • 《深入理解Java虛擬機:JVM高級特性與最佳實踐》電子書.pdf
  • 深入理解 Java 虛擬機(JVM 高級特性與最佳實踐).pdf
  • 深入理解 Java 虛擬機(JVM 高級特性與最佳實踐).pdf
  • 深入理解 Java 虛擬機(JVM 高級特性與最佳實踐).pdf
  • 實戰Java虛擬機 - JVM 故障診斷與性能調優-試讀.pdf
  • JVM調優總結.pdf
  • JVM調優實戰.doc
  • JVM調優總結(十) - 調優方法.docx
  • JVM監控調優.doc

總結

以上是生活随笔為你收集整理的深入理解JVM性能调优的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。