1. 类加载机制分析
Java类(.java) --> 字节码文件(.class)--> 字节码文件需要被加载到JVM内存中(这个过程就是一个类加载的过程)
类加载器(ClassLoader,说白了也是一个类),jvm启动的时候先把类加载器读取到内存中去。
1.1 JVM类加载机制
jvm类加载机制中有一个非常重要的角色叫做类加载器(ClassLoader),类加载器有自己的体系。JVM内置了几种类加载器:引导类加载器,扩展类加载器,系统类加载器,他们之间形成父子关系,通过Parent属性来定义这种关系,最终形成树形结构
image-20200618085533750.png类加载器 | 作用 |
---|---|
引导类加载器<br />BootstrapClassLoader | c++编写,加载java核心库java.*,比如rt.jar中的类。构造ExtClassLoader和APPClassLoader |
扩展类加载器<br />ExtClassLoader | java编写,加载扩展库JAVA_HOME/lib/ext目录下的jar中的类,如classpath中的jre,javax.*或者java.ext.dir指定位置中的类 |
系统类加载器<br />SystemClassLoader/AppClassLoader | 默认的类加载器,搜索环境变量classpath中指明的路径 |
另外:用户可以自定义类加载器(Java编写,用户自定义的类加载器,可加载指定路径的class文件)
当JVM运行过程中,用户自定义了类加载器去加载某些类时,会按照以下的步骤(父类委托机制)
1)用户自己的类加载器,把加载请求传给父类加载器,父加载器再传给其父加载器,一直到加载器树的顶层
2)最顶层的类加载器首先针对其特定的位置加载,如果加载不到就转交给子类
3)如果一直到底层的类加载器都没有加载到,那么就会抛出异常ClassNotFoundException
因此,按照这个过程可以想到,如果同样在 classpath 指定的目录中和自己工作的目录中存放相同的class,会优先加载 classpath 目录中的文件
1.2 双亲委派机制
1.2.1 什么是双亲委派机制
当某个类加载器需要加载某个 .class 文件时,它首先把这个任务委托给他的上级类加载器,递归这个操作,如果上级的类加载器没有加载,自己才会去加载这个类。
1.2.2 双亲委派机制的作用
-
防止加载同一个 .class 文件。通过委托机制向上面问一问,加载过来,就不用再加载一遍。保证数据安全
-
保证核心 .class 不能被篡改。通过委托方式,不会去篡改核心 .class,即使篡改也不会去加载,即使加载也不会是同一个 .class 对象了。不同的加载器加载同一个 .class 也不是同一个 .class 对象。这样保证了class 执行安全(如果子类加载器先加载,那么我们可以写一些与java.lang包中基础类同名的类,然后再定义一个子类加载器,这样整个应用使用的基础类就都变成我们自己定义的类了)。
Object类 -----> 自定义类加载器(会出现问题,那么真正的Object类就可能被篡改了)
1.3 Tomcat 的类加载机制
Tomcat 的类加载机制相对于 JVM 的类加载机制做了一些改变。
没有严格的遵从双亲委派机制,也可以说打破了双亲委派机制。
比如:有一个tomcat,webapps下部署了两个应用
app1/lib/a-1.0.jar com.app.Abc
app2/lib/a-2.0.jar com.app.Abc
不同的版本中Abc类的内容是不同的,代码是不一样的。如果完全遵从双亲委派机制,两个应用下Abc只会被加载一个,这样就是有问题的。
image-20200618092516674.png-
引导类加载器 和 扩展类加载器 作用不变
-
系统类加载器正常情况下加载的是 CLASSPATH 下的类,但是 Tomcat 的启动脚本并未使用该变量,而是加载 Tomcat 启动的类,比如 bootstrap.jar,通常在 catalina.bat 或者 catalina.sh 中指定,位于 CATALINA_HOME/bin 下
-
Common 通用类加载器加载 Tomcat 使用以及应用通用的一些类,位于 CATALINA_PATH/lib 下,比如servlet-api.jar
-
Catalina ClassLoader 用于加载服务器内部可见类,这些类应用程序不能访问
-
Shared ClassLoader 用于加载应用程序共享类,这些类服务器不会依赖
-
WebApp ClassLoader,每个应用程序都还有一个独一无二的 WebApp ClassLoader , 他用来加载本应用程序 /WEB-INF/classes 和 /WEB-INF/lib 下的类。
tomcat 8.5 默认改变了严格的双亲委派机制
- 首先从 Bootstrap ClassLoader 加载指定的类
- 如果未加载到,则从 /WEB-INF/classes 加载
- 如果未加载到,则从 /WEB-INF/lib 加载
- 如果未加载到,则依次从 System、Common、Shared加载(在最后一步,遵从双亲委派机制)
2. Tomcat 优化性能策略
系统性能的衡量指标,主要是响应时间和吞吐量。
响应时间:执行某个操作的耗时。
吞吐量:系统在给定时间内能够支持的事务数量,单位为TPS(Transactions PerSencod的缩写,也就是事务数/秒,一个事务是指一个客户机向服务器发送请求然后服务器做出反应的过程)。
Tomcat 优化从两方面进行
1)JVM虚拟机优化(优化内存模型)
2)Tomcat 自身配置优化(比如是否使用共享线程池?IO模型?)
优化原则:
优化是一个过程,没有明确的参数值供使用,必须根据自己的真实生产环境来进行调整。
2.1 虚拟机运行优化
Java 虚拟机的运行优化主要分为内存分配和垃圾回收策略的优化:
- 内存直接影响服务的运行效率和吞吐量
- 垃圾回收机制会不同程度的导致程序运行中断(垃圾回收策略不同,垃圾回收次数和回收效率都是不同的)
2.1.1 Java 虚拟机内存相关参数
参数 | 参数作用 | 优化建议 |
---|---|---|
-server | 启动server,以服务端模式运行 | 服务端模式建议开启 |
-Xms | 最小堆内存 | 建议与-Xmx设置相同 |
-Xmx | 最大堆内存 | 建议设置为可用内存的80% |
-XX:MetaspaceSize | 元空间初始值 | |
-XX:MaxMetaspaceSize | 元空间最大内存 | 默认无线 |
-XX:NewRatio | 年轻代和老年代大小比值,取值为整数,默认2 | 不需要修改 |
-XX:SurvivorRatio | Eden区和Survivor区大小的比值,取值为整数,默认8 | 不需要修改 |
java内存模型
image-20200618100717019.png参数调整示例
JAVA_OPTS="-server -Xms2048m -Xmx2048m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m"
调整后查看可以使用JDK提供的内存映射工具查看Tomcat中JVM的内存配置
jhsdb jmap --heap --pid xxxx
2.1.2 垃圾回收(GC)策略
垃圾回收性能指标
- 吞吐量:工作时间(排除GC时间)占总时间的百分比,工作时间并不仅是程序的运行时间,还包括内存分配时间
- 暂停时间:由垃圾回收导致的应用程序停止响应次数/时间
垃圾收集器
-
串行收集器(Serial Collector)
单线程执行所有的垃圾回收工作,适用于单核CPU服务器
工作进程 ----- |(暂停) ---- (单线程)垃圾回收线程进行垃圾收集 | ---工作进程继续
-
并行收集器(Parallel Collector)
又称为吞吐量收集器(关注吞吐量),以并行的方式执行年轻代的垃圾回收,该方式可以显著降低垃圾回收开销(指多条垃圾收集器线程并行工作,但此时用户线程任然处于等待状态)。适用于多处理或多线程硬件上运行的数据量较大的应用
工作进程 ----- |(暂停) ---- (多线程)垃圾回收线程进行垃圾收集 | ---工作进程继续
-
并发收集器(Concurrent Collector)
以并发的方式执行大部分垃圾回收工作,以缩短垃圾回收的暂停时间。适用于那些响应时间优于吞吐量的应用,因为该收集器虽然最小化了暂停时间(指用户线程与垃圾收集器线程同时执行,但不一定是并行,可能会交替进行),但是会降低应用的性能。
-
CMS收集器(Concurrent Mark Sweep Collector)
并发标记清除收集器,适用于那些更愿意缩短垃圾回收暂停时间并且负担的起与垃圾回收共享处理器资源的应用
-
G1收集器(Garbage-First Grabage Collector)
适用于大容量内存的多核服务器,可以满足垃圾回收暂停时间目标的同时,以最大可能性实现高吞吐(JDK1.7之后)
垃圾回收参数
参数 | 描述 |
---|---|
-XX:+UseSerialGC | 启用串行收集器 |
-XX:+UseParallelGC | 启用并行收集器,配置了该选项,那么 -XX:+UseParallelOldGC 默认启用 |
-XX:+UseParNewGC | 年轻代请用并行收集器,如果设置了 -XX:+UseConcMarkSweepGC 选项,自动启动 |
-XX:ParallelGCThreads | 年轻代以及老年代垃圾回收使用的线程数。默认值依赖于JVM使用的CPU个数 |
-XX:+UseConcMarkSweepGC(CMS) | 对应老年代,启用CMS垃圾收集器。当并行收集器无法满足应用的延迟需求时,推荐使用CMS或G1收集器。启用该选项后,-XX:+UseParallelGC 自动启用 |
-XX:+UseG1GC | 启用G1收集器,G1是服务器类型的收集器,用于多核、大内存的机器。它在保持高吞吐量的情况下,高概率的满足GC暂停时间的目标 |
在 bin/catalina.sh 的脚步中,追加配置:
JAVA_OPTS="-XX:+UseConcMarkSweepGC"
2.2 Tomcat 配置优化
Tomcat 自身相关优化
网友评论