首頁>技術>

背景

目前,有很多公司的WEB伺服器會出現CPU、記憶體、IO告警,運維人員往往不能及時地獲取JVM等相關資訊,以便分析造成告警的原因,故本文將從幾個方面來闡述如何進行JVM快照,如何分析dump的快照檔案,以及TOMCAT調優,JVM引數調優設定和程式程式碼書寫需要注意的問題。

JVM學習

首先,我們來看一下Java中的記憶體模型:

圖 1

Dump JVM快照及分析Java VisualVM工具Jmap自動化獲取快照效能調優Tomcat容器調優

這裡以Tomcat7舉例說明,Tomcat7容器調優主要是在server.xml檔案中對connector進行調優,新增相關屬性,實現高併發。

server.xml配置

<Connector port="8080"protocol="HTTP/1.1" maxThreads="30000"

minSpareThreads="512" maxSpareThreads="2048" enableLookups="false"

redirectPort="8443" acceptCount="35000" debug="0" connectionTimeout="40000"

disableUploadTimeout="true" URIEncoding="UTF-8" />

引數說明:

connectionTimeout

網路連線超時,單位:毫秒。設定為0表示永不超時,這樣設定有隱患的。通常可設定為30000毫秒。

keepAliveTimeout

長連線最大保持時間(毫秒)。此處為15秒。

maxKeepAliveRequests

最大長連線個數(1表示禁用,-1表示不限制個數,預設100個。一般設定在100~200之間)

maxHttpHeaderSize

http 請求頭資訊的最大程度,超過此長度的部分不予處理。一般8K。

URIEncoding

指定Tomcat 容器的URL 編碼格式。

acceptCount

指定當所有可以使用的處理請求的執行緒數都被使用時,可以放到處理佇列中的請求數,超過這個數的請求將不予處理,預設為10個。

disableUploadTimeout

上傳時是否使用超時機制

enableLookups

是否反查域名,取值為:true 或false。為了提高處理能力,應設定為false

maxSpareThreads

最大空閒連線數,一旦建立的執行緒超過這個值,Tomcat 就會關閉不再需要的socket執行緒The default value is 50.

maxThreads

最多同時處理的連線數,Tomcat 使用執行緒來處理接收的每個請求。這個值表示Tomcat 可建立的最大的執行緒數。

minSpareThreads

最小空閒執行緒數,Tomcat 初始化時建立的執行緒數.

minProcessors

最小空閒連線執行緒數,用於提高系統處理效能,預設值為10。

maxProcessors

最大連線執行緒數,即:併發處理的最大請求數,預設值為75

JVM調優程式開發注意事項

程式開發時,如果不理解JVM,很可能會造成記憶體溢位、棧溢位等問題。

堆溢位

public class HeapOOM {

static class OOMObject{}

/**

* @param args

*/

public static void main(String[] args) {

List<OOMObject> list = new ArrayList<OOMObject>();

while(true){

list.add(new OOMObject());

}

}

}

分析:

我們上面看到堆主要是存放物件的,所以我們如果想讓堆出現OOM的話,可以開一個死迴圈,然後產生新的物件就可以了。然後再將堆的大小調小點。

加上JVM引數

-verbose:gc -Xms10M -Xmx10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+HeapDumpOnOutOfMemoryError,

就能很快報出OOM:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space。

棧溢位

package com.cutesource;

public class StackOOM {

/**

* @param args

*/

private int stackLength = 1;

public void stackLeak(){

stackLength++;

stackLeak();

}

public static void main(String[] args) throws Throwable{

// TODO Auto-generated method stub

StackOOM oom = new StackOOM();

try{

oom.stackLeak();

}catch(Throwable err){

System.out.println("Stack length:" + oom.stackLength);

throw err;

}

}

}

分析:

我們知道棧中存放的方法執行的過程中需要的空間,所以我們可以下一個迴圈遞迴,這樣方法棧就會出現OOM的異常了。

設定JVM引數:-Xss128k,報出異常:

Exception in thread "main" java.lang.StackOverflowError

打印出Stack length:1007,這裡可以看出,在我的機器上128k的棧容量能承載深度為1007的方法呼叫。

方法區溢位

public class MethodAreaOOM {

static class OOMOjbect{}

/**

* @param args

*/

public static void main(String[] args) {

// TODO Auto-generated method stub

while(true){

Enhancer eh = new Enhancer();

eh.setSuperclass(OOMOjbect.class);

eh.setUseCache(false);

eh.setCallback(new MethodInterceptor(){

@Override

public Object intercept(Object arg0, Method arg1,

Object[] arg2, MethodProxy arg3) throws Throwable {

// TODO Auto-generated method stub

return arg3.invokeSuper(arg0, arg2);

}

});

eh.create();

}

}

}

分析:

我們知道方法區是存放一些類的資訊等,所以我們可以使用類載入無限迴圈載入class,這樣就會出現方法區的OOM異常。

手動將棧的大小調小點

加上JVM引數:-XX:PermSize=10M -XX:MaxPermSize=10M,執行後會報如下異常:

Exception in thread "main" java.lang.OutOfMemoryError: PermGen space。

常量池溢位

public class ConstantOOM {

/**

* @param args

*/

public static void main(String[] args) {

// TODO Auto-generated method stub

List<String> list = new ArrayList<String>();

int i=0;

while(true){

list.add(String.valueOf(i++).intern());

}

}

}

分析:

我們知道常量池中存放的是執行過程中的常量,同時我們知道String型別的intern方法是將字串的值放到常量池中的。所以上面弄可以開一個死迴圈將字串的值都放到常量池中,這樣常量池就會出現OOM異常了。因為常量池本身就是方法區的一部分,所以我們也可以手動地調節一下棧的大小。

推薦:

《深入理解Java虛擬機器》

3
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 如何編寫最有效有價值的YouTube描述 - 油管最佳化小技巧