jvm优化-c

1 tomcat8优化

1.1 tomcat配置优化

部署安装

1.1.1 修改配置文件,配置tomcat的管理用户
# vi apache-tomcat-8.5.34/conf/tomcat-users.xml
<role rolename="manager"/>
<role rolename="manager-gui"/>
<role rolename="admin"/>
<role rolename="admin-gui"/>
<user username="tomcat" password="maggie" roles="admin-gui,admin,manager-gui,manager"/>

#tomcat8还需要配置
vi webapps/manager/META-INF/context.xml
将value的内容注释掉。
<Context antiResourceLocking="false" privileged="true" >
  <Valve className="org.apache.catalina.valves.RemoteAddrValve"
         allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />
  <Manager sessionAttributeValueClassNameFilter="java\.lang\.(?:Boolean|Integer|Long|Number|String)|org\.apache\.catalina\.filters\.CsrfPreventionFilter\$LruCache(?:\$1)?|java\.util\.(?:Linked)?HashMap"/>
</Context>

# 启动tomcat
cd apache-tomcat-8.5.34/bin/
./startup.sh && tail -f ../logs/catalina.out

# 打开浏览器访问
http://116.62.108.24:8080
1.1.2 禁用AJP连接
修改server.xml,注释下面这行
  <!-- Define an AJP 1.3 Connector on port 8009 -->
    <!--<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> -->
1.1.3 执行器(线程池)

tomcat中没一个用户请求都是一个线程,可以使用线程池提高性能。

修改server.xml文件

# 放开注释
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-" maxThreads="500" minSpareThreads="50" prestartminSpareThreads="true" maxQueueSize="100"/>
<!-- 
参数说明:
maxThreads:最大并发数,默认为200,一般建议在500~1000,根据硬件设施和业务来判断
minSpareThreads: Tomcat初始化时创建的线程数,默认设置25
prestartminSpareThreads:在tomcat初始化的时候就初始化minSpareThreads参数,如果不等于true,minSpareThreads值就没啥效果
maxQueueSize:最大的等待队列数,超过则拒绝请求
-->
...
# 放开注释引用上面的执行器
<Connector executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1"  connectionTimeout="20000" redirectPort="8443" />
1.1.4 三种运行模式
设置nio2
<Connector port="8080" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
               connectionTimeout="20000"
               redirectPort="8443" />

1.2 部署测试用的java web项目

1.2.1 执行 dashboard.sql

cat dashboard.sql | mysql -h rm-bp14byw6s6kc846nl125010.mysql.rds.aliyuncs.com -P 3306 -u zephyr -p

1.2.2 部署web应用
cd servers/apache-tomcat-8.5.34/webapps
rm -rf *
mkdir ROOT
cd ROOT

rz 
jar -xvf itcat-dashboard-web.war 
rm -rf itcat-dashboard-web.war

# 修改数据库配置文件
cd /apache-tomcat-8.5.34/webapps/ROOT/WEB-INF/classs
vi jdbc.propertise
# 修改数据库配置

# 重启服务

1.3 使用Apache Jmeter进行测试

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-seRr3nEM-1588240638556)(D:\exquisite\mynote\jvm\images\image-20200417100400573.png)]

1.4 调整tomcat参数进行优化

1.4.1 禁用AJP服务
#修改server.xml,注释下面这行
<!-- Define an AJP 1.3 Connector on port 8009 -->
<!--<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> -->

可以看到禁用ajp后,吞吐量有提升。

1.4.2 设置线程池
1.4.2.1 最大线程数为500,初始为50
server.xml
# 设置线程池
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-" maxThreads="500" minSpareThreads="50" prestartminSpareThreads="true"/>
# 放开注释引用上面的执行器,这里要删除上一个重复的connector
<Connector executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1"
connectionTimeout="20000" redirectPort="8443" />
1.4.2.2 最大线程数为1000,初始为200
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-" maxThreads="1000" minSpareThreads="200" prestartminSpareThreads="true"/>
1.4.2.3 最大线程数为5000,初始为1000
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-" maxThreads="5000" minSpareThreads="1000" prestartminSpareThreads="true"/>
1.4.2.4 设置最大等待队列
#设置等待队列
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-" maxThreads="500" minSpareThreads="100" prestartminSpareThreads="true" maxQueueSize="100"/>
1.4.3 设置nio2的运行模式
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-" maxThreads="500" minSpareThreads="50" prestartminSpareThreads="true" maxQueueSize="100"/>
# 设置nio2
<Connector port="8080" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
               connectionTimeout="20000"
               redirectPort="8443" />

1.5 调整JVM参数进行优化

在最大线程为500,启用nio2的模式运行的前提下继续优化。

1.5.1 设置并行垃圾回收器
# vi bin/catalina.sh
# 年轻代、老年代均使用并行垃圾收集器,初始堆内存64M,最大堆内存512M
JAVA_OPTS="-XX:+UseParallelGC -XX:+UseParallelOldGC -Xms64m -Xmx512m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:/export/servers/tomcat/logs/gc.log"

# 这里配置log路径为全路径即可,配置为相对路径(-Xloggc:../logs/gc.log)未能生成文件

# 打印的日志增加时间戳
JAVA_OPTS="-XX:+UseParallelGC -XX:+UseParallelOldGC -Xms64m -Xmx512m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:/export/servers/tomcat/logs/gc-`date +%Y%m%d%H%M`.log"
1.5.2 查看gc日志文件

网站在线分析gc.log http://gceasy.io

若查看到 System Time greater than User Time

  • 系统消耗的时间大于用户时间,反映出服务器性能存在瓶颈,调度CPU等资源消耗时间长
  • Throughput 吞吐量和Avg Pause GC Time、Max Pause GC Time (线程暂停时间)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Lo8uWw7d-1588240638560)(D:\exquisite\mynote\jvm\images\image-20200418211332210.png)]

  • Total GC stats GC的总统计) Minor GC stats(年轻代GC统计) Full GC stats (FullGC统计)GC Pause Statistics (GC时暂停统计)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-70xa5U7N-1588240638562)(D:\exquisite\mynote\jvm\images\image-20200418211531383.png)]

  • 触发GC的原因

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2fx1ntFq-1588240638566)(D:\exquisite\mynote\jvm\images\image-20200418213112111.png)]

数据解释:
# jdk8中永久代(PermGen)的概念被废弃掉了,取而代之的是一个称为Metaspace的存储空间。Metaspace使用的是本地内存,而不是堆内存,也就是说在默认情况下Metaspace的大小只与本地内存大小有关;
# JDK8中,XX:MaxMetaspaceSize确实是没有上限的,最大容量与机器的内存有关;但是XX:MetaspaceSize是有一个默认值的:21M,设置一个XX:MetaspaceSize的JVM启动参数:-XX:MetaspaceSize=128M
JAVA_OPTS="-XX:+UseParallelGC -XX:+UseParallelOldGC -Xms64m -Xmx512m -XX:MetaspaceSize=128M -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:/export/servers/tomcat/logs/gc.log"

设置一个XX:MetaspaceSize的JVM启动参数:-XX:MetaspaceSize=128M 
如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5JTZgeH6-1588240638569)(D:\exquisite\mynote\jvm\images\image-20200418214641014.png)]

Ergonomics翻译成中文,一般都是“人体工程学”。在JVM中的垃圾收集器中的Ergonomics就是负责自动的调解gc暂停时间和吞吐量之间的平衡,然后你的虚拟机性能更好的一种做法。
1.5.3 调整年轻代大小
# 将初始堆大小设置为128m,最大为1024m, 初始年轻代大小为64m,年轻代最大256m
# vi bin/catalina.sh
# -xx:NewSize=64m 我的阿里云,这样设置会报错:Unrecognized option: -xx:NewSize=64m

# -Xmn64m 设置年轻代大小的方式
JAVA_OPTS="-XX:+UseParallelGC -XX:+UseParallelOldGC -Xms128m -Xmx1024m -Xmn64m -XX:MaxNewSize=256m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:/export/servers/tomcat/logs/gc.log"

看到GC次数要明显减少,说明调整有效

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qANcc9Pq-1588240638570)(D:\exquisite\mynote\jvm\images\image-20200418220910722.png)]

1.5.4 设置G1垃圾回收器
# vi bin/catalina.sh
# 年轻代、老年代均使用并行垃圾收集器,初始堆内存64M,最大堆内存512M
JAVA_OPTS="-XX:+UseG1GC -XX:MaxGCPauseMillis=100 -Xms128m -Xmx1024m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:/export/servers/tomcat/logs/gc.log"

# 吞吐量提升,平均响应时间缩短

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kcFueDCg-1588240638571)(D:\exquisite\mynote\jvm\images\image-20200418221013279.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZdCQ5Yv3-1588240638573)(D:\exquisite\mynote\jvm\images\image-20200418221930146.png)]

1.5.5 小结

不断的调整测试,可能调差也可能调好,gc在easy,io中查看回收情况。

2 JVM字节码

2.1 通过javap命令查看class文件的字节码

public class Test1 {
    public static void main(String[] args) {
        int a = 2;
        int b = 5;
        int c = b - a;
        System.out.println(c);
    }
}

通过javap命令查看class文件中的字节码内容:

javac Test1.java

javap -v Test1.class > Test1.txt

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IMlHBsQu-1588240638574)(D:\exquisite\mynote\jvm\images\image-20200418222244804.png)]

Classfile /D:/exquisite/code/lf-jvm/jvm-test/src/main/java/cn/zephyr/jvm/Test1.class
  Last modified 2020-4-18; size 414 bytes
  MD5 checksum 9d961ef8b964df7db9afbc014472dd41
  Compiled from "Test1.java"
public class cn.zephyr.jvm.Test1
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #5.#14         // java/lang/Object."<init>":()V
   #2 = Fieldref           #15.#16        // java/lang/System.out:Ljava/io/PrintStream;
   #3 = Methodref          #17.#18        // java/io/PrintStream.println:(I)V
   #4 = Class              #19            // cn/zephyr/jvm/Test1
   #5 = Class              #20            // java/lang/Object
   #6 = Utf8               <init>
   #7 = Utf8               ()V
   #8 = Utf8               Code
   #9 = Utf8               LineNumberTable
  #10 = Utf8               main
  #11 = Utf8               ([Ljava/lang/String;)V
  #12 = Utf8               SourceFile
  #13 = Utf8               Test1.java
  #14 = NameAndType        #6:#7          // "<init>":()V
  #15 = Class              #21            // java/lang/System
  #16 = NameAndType        #22:#23        // out:Ljava/io/PrintStream;
  #17 = Class              #24            // java/io/PrintStream
  #18 = NameAndType        #25:#26        // println:(I)V
  #19 = Utf8               cn/zephyr/jvm/Test1
  #20 = Utf8               java/lang/Object
  #21 = Utf8               java/lang/System
  #22 = Utf8               out
  #23 = Utf8               Ljava/io/PrintStream;
  #24 = Utf8               java/io/PrintStream
  #25 = Utf8               println
  #26 = Utf8               (I)V
{
  public cn.zephyr.jvm.Test1();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 3: 0

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=4, args_size=1
         0: iconst_2
         1: istore_1
         2: iconst_5
         3: istore_2
         4: iload_2
         5: iload_1
         6: isub
         7: istore_3
         8: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        11: iload_3
        12: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
        15: return
      LineNumberTable:
        line 6: 0
        line 7: 2
        line 8: 4
        line 9: 8
        line 10: 15
}
SourceFile: "Test1.java"

2.2 常量池

https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.4-140

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d3WPVNbI-1588240638575)(D:\exquisite\mynote\jvm\images\image-20200418222637638.png)]

2.3 字段描述符

https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.3.2

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RJHhRdCF-1588240638576)(D:\exquisite\mynote\jvm\images\image-20200418222803495.png)]

2.4 方法描述符

https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.3.3

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K4tC1FXe-1588240638577)(D:\exquisite\mynote\jvm\images\image-20200418223102753.png)]

2.4 解读方法字节码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JHvcVQ7U-1588240638578)(D:\exquisite\mynote\jvm\images\image-20200418223607676.png)]

3 代码优化

  • 尽可能使用局部变量

  • 尽量减少对变量的重复计算

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4WANxrna-1588240638578)(D:\exquisite\mynote\jvm\images\image-20200418223743823.png)]

  • 尽量采用懒加载的策略,即在需要的时候才创建对象

  • 异常不应该用来控制程序流程

  • 不要将数组声明为putlic static final

  • 不要创建一些不使用的对象,不要导入一些不使用的类

  • 程序运行过程中避免使用反射

  • 使用数据库连接池和线程池

  • 容器初始化时候尽可能指定长度

    • new ArrayList<>(10)
  • ArrayList随机遍历快,LinkedList添加删除快

  • 使用Entry遍历Map

  • 不要手动调用System.gc()

  • String 尽量少用正则表达式

  • 日志输出要注意级别

  • 对资源的close建议分开操作

  • 尽量减少对变量的重复计算

[外链图片转存中…(img-4WANxrna-1588240638578)]

  • 尽量采用懒加载的策略,即在需要的时候才创建对象

  • 异常不应该用来控制程序流程

  • 不要将数组声明为putlic static final

  • 不要创建一些不使用的对象,不要导入一些不使用的类

  • 程序运行过程中避免使用反射

  • 使用数据库连接池和线程池

  • 容器初始化时候尽可能指定长度

    • new ArrayList<>(10)
  • ArrayList随机遍历快,LinkedList添加删除快

  • 使用Entry遍历Map

  • 不要手动调用System.gc()

  • String 尽量少用正则表达式

  • 日志输出要注意级别

  • 对资源的close建议分开操作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-icCLHbGa-1588240638580)(D:\exquisite\mynote\jvm\images\image-20200418224150231.png)]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值