<返回更多

互联网云服务器JVM监控——JDK自带工具

2021-03-12    
加入收藏

背景

目前,有很多公司的WEB服务器会出现CPU、内存、IO告警,运维人员往往不能及时地获取JVM等相关信息,以便分析造成告警的原因,故本文将从几个方面来阐述如何进行JVM快照,如何分析dump的快照文件,以及Tomcat调优,JVM参数调优设置和程序代码书写需要注意的问题。

JVM学习

首先,我们来看一下JAVA中的内存模型:

互联网云服务器JVM监控——JDK自带工具

图 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虚拟机》

声明:本站部分内容来自互联网,如有版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
▍相关推荐
更多资讯 >>>