热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Tomcat的性能优化及JVM内存工作原理

JVM性能优化原则:代码运算性能、内存回收、应用配置(影响Java程序主要原因是垃圾回收机制)代码层优化:避免过多循环嵌套、调用和复杂逻辑。Tomcat调优主要内容1、

JVM性能优化原则:代码运算性能、内存回收、应用配置(影响Java程序主要原因是垃圾回收机制)
代码层优化:避免过多循环嵌套、调用和复杂逻辑。

Tomcat调优主要内容

1、增加最大连接数

2、调整工作模式

3、启用gzip压缩

4、调整JVM内存大小

5、作为web服务器时、无Apache整合或者nginx

6、合理选择垃圾回收算法

7、尽量使用较新的JDK版本

生产配置实例

   #可支持压缩的文件类型

Tomcat的运行模式

Tomcat有三种工作模式:Bio、Nio和Apr

Bio(Blocking I/O):默认工作模式,一个线程处理一个请求,在高并发的的环境下,线程数较多,浪费资源,没有任何优化技术处理,性能比较低

Nio(New I/O or Non-Blocking):非阻塞式I/O模式,NIO主要是利用Java的异步I/O处理,可以通过少量的线程处理大量的请求

Apr(Apache Portable Runtime,Apathe可移植运行库):Tomcat运行高并发应用的首选工作模式,APR是从操作系统层面解决IO阻塞问题,大幅度提高服务器的处理和响应性能

启动Apr模式的方法

1)安装依赖库 

[root@tomcat ~]# yum install -y apr-devel openssl-devel gcc make

[root@tomcat ~]# rpm -qa | grep openssl
openssl-libs-1.0.2k-12.el7.x86_64
openssl-devel-1.0.2k-12.el7.x86_64
openssl-1.0.2k-12.el7.x86_64

2)安装apr动态库

在安装apr动态库之前,需要java环境,在这里,有个坑需要注意,那就是ap在预编译的之后一定要有jdk环境,我们一般安装都是直接yum install -y java一条命令搞定,但是呢,在这里是不支持的,

需要手动配置才行,否则便会报错

配置环境变量

export JAVA_HOME=/usr/java/jdk1.7.0_65
export CLASSPATH=$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib
export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH:$HOMR/bin

下载Tomcat-native包

地址:https://archive.apache.org/dist/tomcat/tomcat-connectors/native/1.2.17/source/tomcat-native-1.2.17-src.tar.gz

[root@tomcat ~]# wget https://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomcat-connectors/native/1.2.17/source/tomcat-native-1.2.17-src.tar.gz    #下载包

[root@tomcat ~]# tar zxvf tomcat-native-1.2.17-src.tar.gz -C /usr/local/tomcat/bin/      #解压

[root@tomcat ~]# cd /usr/local/tomcat/bin/tomcat-native-1.2.17-src/native/     #移动到指定目录
 
[root@tomcat native]# make && make install    #编译安装
[root@tomcat native]# ll /usr/local/apr/lib/    #查看是否成功
total 3268
-rw-r--r-- 1 root root 2121194 Jun 30 16:28 libtcnative-1.a
-rwxr-xr-x 1 root root 1027 Jun 30 16:28 libtcnative-1.la
lrwxrwxrwx 1 root root 23 Jun 30 16:28 libtcnative-1.so -> libtcnative-1.so.0.2.17
lrwxrwxrwx 1 root root 23 Jun 30 16:28 libtcnative-1.so.0 -> libtcnative-1.so.0.2.17
-rwxr-xr-x 1 root root 1204408 Jun 30 16:28 libtcnative-1.so.0.2.17
drwxr-xr-x 2 root root 4096 Jun 30 16:28 pkgconfig

配置APR本地库到系统共享库搜索路径  # vim /usr/local/tomcat/bin/catalina.sh

JAVA_OPTS="$JAVA_OPTS -Djava.library.path=/usr/local/apr/lib/"   #在虚拟机启动参数JAVA_OPTS中添加java.library.path参数,指定apr库的路径

实现原理:Tomcat利用基于Apr库tomcat-native来实现操作系统级别控制,提供一种优化技术和非阻塞式I/O操作,大大提高并发处理能力。但需要安装Apr和tomcat-native库。

工作模式原理涉及了网络I/O模型知识

阻塞式I/O模型:应用进程调用recv函数系统调用时,如果等待要操作的数据没有发送到内核缓存区,应用进程将阻塞,不能接收其它请求。反之内核recv端缓冲区有数据,内核会把数据复制到用户空间解除阻塞,继续处理下一个请求。(内核空间(缓冲区)--用户空间(系统调用))

非阻塞式I/O模型:应用进程设置成非阻塞模式,如果要操作的数据没有发到内核缓冲区,recv系统调用返回一个错误,应用进程利用轮询方式不断检查此操作是否就绪,如果缓冲区有数据则返回,I/O操作同时不会阻塞应用进程,期间会继续处理新请求。

I/O复用模型:阻塞发生在select/poll的系统调用上,而不是阻塞在实际的I/O系统调用上。能同时处理多个操作,并检查操作是否就绪,select/epoll函数发现有数据就绪后,就通过实际I/O操作将数据复制到应用进程缓存区中。

异步I/O模型:应用进程通知内核开始第一个异步I/O操作,并让内核在整个操作(包括数据复制缓冲区)完成后通知应用进程,期间会继续处理新请求。

I/O操作分为两个阶段:第一个阶段等待数据可用,第二个阶段将数据从内核复制到用户空间。

前三种模型的区别:第一阶段阻塞式I/O阻塞在I/O操作上,非阻塞式I/O轮询,I/O复用阻塞在select/poll或epoll上。第二个阶段都是一样的。而异步I/O的两个阶段都不会阻塞进程。

Java性能问题主要来自JVM,JVM  GC也比较复杂,相关基础概念###

1、JVM内存划分为年轻代、老年代、永久代。

2、年轻代又分为: Eden和Survivor区由FromSpace和ToSpace组成。Eden区占大容量,Survivor两个区占小容量,默认比例大概是8:2。

3、堆内存(Heap)=年轻代+老年代。非堆内存=永久代。

4、堆内存用途: 存放的对象,垃圾收集器就是收集这些对象,然后根据GC算法回收。

5、非堆内存用途:JVM本身是用,存放一些类、方法、常量、属性等。

6、年轻代: 新生成的对象首先放到年轻代的Eden区中,当Eden满时,经过GC后,还存活的对象被复制到Survivor区的FromSpace中,如果Survivor区满时,会再被复制到Survivor区的ToSpace区。如果还有存活对象,会再被复制到老年代。

7、老年代:在年轻代中经过GC后还存活的对象会被复制到老年代中。当老年代空间不足时,JVM会对老年代进行完全的垃圾回收(Full GC)。如果GC后,还是无法存放从Survivor区复制过来的对象,就会出现OOM(Out of Memory)。

8、永久代:也成为方法,存放静态类型数据,比如类、方法、属性等

垃圾回收(GC,garbage collection)算法

1、标记-清除(Mark-Sweep)

GC分为两个阶段,标记和清除。首先标记所有可回收的对象,在标记完成后统一回收所有被标记的对象。同时会产生不连续的内存碎片。碎片过多会导致以后程序运行时需要分配较大对象时,无法找到足够的连续内存,而不得以再次触发GC。

2、复制(copy)

将内存按容量划分为两块,每次只使用其中一块。当着一块用完了,就将存活的对象复制到另一块上,然后再把已使用的内存空间一次清理掉,这样使得每次对半个内存区在回收,也不用考虑内存碎片问题,简单高效。缺点需要两倍的内存空间。

3、标记-整理(Mark-Compact)

也分为两个阶段,首先标记可回收的对象,再将存活的对象都向一端移动,然后清理掉边界以外的内存。此方法避免标记-清除算法的碎片问题,同时也避免了复制算法的空间问题。

一般年轻代中执行GC后,会有少量的对象存活,就会选用复制算法,只要付出少量的存货成本就可以完成收集。而老年代中因对象存活率高,没有额外过多内存空间分配,就需要使用标记-清理或标记-整理算法来进行回收。

垃圾收集器

1、串行收集器(Serial

比较老的收集器,单线程。收集时,必须暂停应用的工作线程,直到收集结束。

2、并行收集器(parallel)

多线程并行工作,在多核CPU下效率更高,应用线程依然处于等待状态。

3、CMS收集器(concurrent Mark sweep)

  1. 初始标记(Initial Mark)

  2. 并发标记(Concurrent Mark)

  3. 重新标记(Remark)

  4. 并发清除(Concurrent Sweep)

初始标记、重新标记这两个步骤仍然需要暂停应用线程。初始标记只是标记一下GC Roots能直接关联的对象,速度很快,并发标记阶段是标记可回收对象,而重新标记阶段则是为了修正并发标记期间因用户程序继续运行导致
标记产生变动的那一部分对象的标记记录,这个阶段暂停时间比初始标记阶段稍长一点,但远比并发标记时间段。

由于整个过程中消耗最长的并发标记和并发清除过程收集器线程都可以与用户线程一起工作,所以,CMS收集器内存回收与用户一起并发执行的,大大减少了暂停时间。

4、G1收集器(Garbage First)
G1收集器将堆内存划分多个大小相等的独立区域(Region),并且能预测暂停时间,能预测原因它能避免对整个堆进行全区收集。G1跟踪各个Region里的垃圾堆积价值大小(所获得空间大小以及回收所需时间),在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region,从而保证了再有限时间内获得更高的收集效率。

G1收集器工作工程分为4个步骤,包括:

初始标记(Initial Mark)

并发标记(Concurrent Mark)

最终标记(Final Mark)

筛选回收(Live Data Counting and Evacuation)

初始标记与CMS一样,标记一下GC Roots能直接关联到的对象。并发标记从GC Root开始标记存活对象,这个阶段耗时比较长,但也可以与应用线程并发执行。而最终标记也是为了修正在并发标记期间因用户程序继续运作而导致标记产生变化的那一部分标记记录。最后在筛选回收阶段对各个Region回收价值和成本进行排序,根据用户所期望的GC暂停时间来执行回收。

了解了JVM基础知识,下面配置下相关Java参数,将下面一段放到catalina.sh里面:

JAVA_OPTS="-server -Xms1024m -Xmx1536m -XX:PermSize=256m -XX:MaxPermSize=512m -XX:+UseConcMarkSweepGC -XX:+UseParallelGCThreads=8 XX:CMSInitiatingOccupancyFraction=80 -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:-PrintGC -XX:-PrintGCDetails -XX:-PrintGCTimeStamps -Xloggc:../logs/gc.log"

-Xms

堆内存初始大小,单位m、g

-Xmx

堆内存最大允许大小,一般不要大于物理内存的80%

-XX:PermSize

非堆内存初始大小,一般应用设置初始化200m,最大1024m就够了

-XX:MaxPermSize

非堆内存最大允许大小

-XX:+UseParallelGCThreads=8

并行收集器线程数,同时有多少个线程进行垃圾回收,一般与CPU数量相等

-XX:+UseParallelOldGC

指定老年代为并行收集

-XX:+UseConcMarkSweepGC

CMS收集器(并发收集器)

-XX:+UseCMSCompactAtFullCollection

开启内存空间压缩和整理,防止过多内存碎片

-XX:CMSFullGCsBeforeCompaction=0

表示多少次Full GC后开始压缩和整理,0表示每次Full GC后立即执行压缩和整理

-XX:CMSInitiatingOccupancyFraction=80%

表示老年代内存空间使用80%时开始执行CMS收集,防止过多的Full GC

注意:不是JVM内存设置越大越好,具体还是根据项目对象实际占用内存大小而定,可以通过Java自带的分析工具来查看。如果设置过大,会增加回收时间,从而增加暂停应用时间。

gzip压缩作用:节省服务器流量和提高网站访问速度。客户端请求服务器资源后,服务器将资源文件压缩,再返回给客户端,由客户端的浏览器负责解压缩并浏览。

使用Apache与Tomcat整合,因为Tomcat处理静态文件能力远不足Apache,因此让Apache来处理静态文件,Tomcat处理动态jsp文件,可以有效提高处理速度。

TomcatSessionID持久化三种方法:

Session粘性:通过浏览器COOKIE绑定SessionID,通过sticky模式将同一Session请求分配到同一Tomcat上。

Session复制:Tomcat通过广播形式将Session同步到其他Tomcat节点,并且Linux下要手动开启开放广播地址。不易后端节点过多

Session保存数据库(memcache、redis):将SessionID保存在共享的数据库中。

OOM(Out of Memory)异常常见有以下几个原因:

1)老年代内存不足:
java.lang.OutOfMemoryError:Javaheapspace

2)永久代内存不足:

java.lang.OutOfMemoryError:PermGenspace

3)代码bug,占用内存无法及时回收。

前两种情况通过加大内存容量,可以得到解决。如果是代码bug,就要通过jstack、jmap、jstat自带的工具分析问题,定位到相关代码,让开发解决。


推荐阅读
  • Java中高级工程师面试必备:JVM核心知识点全面解析
    对于软件开发人员而言,随着技术框架的不断演进和成熟,许多高级功能已经被高度封装,使得初级开发者只需掌握基本用法即可迅速完成项目。然而,对于中高级工程师而言,深入了解Java虚拟机(JVM)的核心知识点是必不可少的。这不仅有助于优化性能和解决复杂问题,还能在面试中脱颖而出。本文将全面解析JVM的关键概念和技术细节,帮助读者全面提升技术水平。 ... [详细]
  • JVM参数设置与命令行工具详解
    JVM参数配置与命令行工具的深入解析旨在优化系统性能,通过合理设置JVM参数,确保在高吞吐量的前提下,有效减少垃圾回收(GC)的频率,进而降低系统停顿时间,提升服务的稳定性和响应速度。此外,本文还将详细介绍常用的JVM命令行工具,帮助开发者更好地监控和调优JVM运行状态。 ... [详细]
  • 深入浅出解析HTTP协议的核心功能与应用
    前言——协议是指预先设定的通信规则,确保双方能够按照既定标准进行有效沟通,从而实现准确的信息交换。例如,驯兽师通过拍手使动物坐下,这实际上是一种预设的协议。本文将详细探讨HTTP协议的核心功能及其广泛应用,解析其在现代网络通信中的重要作用。 ... [详细]
  • 阿里巴巴Java后端开发面试:TCP、Netty、HashMap、并发锁与红黑树深度解析 ... [详细]
  • 在Vite项目优化过程中,通过使用rollup-plugin-visualizer插件,可以有效地对Rollup打包结果进行可视化分析,帮助开发者清晰地了解各个模块的占用情况,从而进行更有针对性的优化。此外,结合其他常用插件,如vite-plugin-compression和vite-plugin-inspect,可以进一步提升项目的性能和可维护性。 ... [详细]
  • 本文详细解析了九度编程平台上的斐波那契数列高效算法挑战(题目编号:1387)。该挑战要求在1秒的时间限制和32兆的内存限制下,设计出高效的斐波那契数列计算方法。通过多种算法的对比和性能分析,本文提供了优化方案,帮助参赛者在限定资源条件下实现高效计算。 ... [详细]
  • 如何在Mac上构建高效的本地服务器环境
    在Mac上构建高效的本地服务器环境,首先需要了解基本步骤:1. 配置目录基础;2. 启动Apache服务;3. 添加自定义文档至本地服务器;4. 查看自定义效果。此外,还可以通过手机或其他电脑访问本机服务器,以确保跨设备的兼容性和调试效果。Mac系统自带的Apache服务为本地开发提供了便捷的工具,本文将详细介绍每个步骤的具体操作方法。 ... [详细]
  • TypeScript 实战分享:Google 工程师深度解析 TypeScript 开发经验与心得
    TypeScript 实战分享:Google 工程师深度解析 TypeScript 开发经验与心得 ... [详细]
  • 从2019年AI顶级会议最佳论文,探索深度学习的理论根基与前沿进展 ... [详细]
  • PHP中元素的计量单位是什么? ... [详细]
  • Python学习:环境配置与安装指南
    Python作为一种跨平台的编程语言,适用于Windows、Linux和macOS等多种操作系统。为了确保本地已成功安装Python,用户可以通过终端或命令行界面输入`python`或`python3`命令进行验证。此外,建议使用虚拟环境管理工具如`venv`或`conda`,以便更好地隔离不同项目依赖,提高开发效率。 ... [详细]
  • 如何正确配置与使用日志组件:Log4j、SLF4J及Logback的连接与整合方法
    在当前的软件开发实践中,无论是开源项目还是日常工作中,日志框架都是不可或缺的工具之一。本文详细探讨了如何正确配置与使用Log4j、SLF4J及Logback这三个流行的日志组件,并深入解析了它们之间的连接与整合方法,旨在帮助开发者高效地管理和优化日志记录流程。 ... [详细]
  • NoSQL数据库,即非关系型数据库,有时也被称作Not Only SQL,是一种区别于传统关系型数据库的管理系统。这类数据库设计用于处理大规模、高并发的数据存储与查询需求,特别适用于需要快速读写大量非结构化或半结构化数据的应用场景。NoSQL数据库通过牺牲部分一致性来换取更高的可扩展性和性能,支持分布式部署,能够有效应对互联网时代的海量数据挑战。 ... [详细]
  • Apache Maven 3.5.0 版本的发布带来了多项重要特性和性能优化。该版本不仅改进了构建过程的效率,还增强了对复杂项目结构的支持。通过引入新的依赖解析机制和优化的插件系统,Maven 3.5.0 在提升用户体验的同时,也确保了更高的稳定性和兼容性。此外,该版本还修复了多个已知问题,进一步提升了整体的可靠性和安全性。 ... [详细]
  • 通过一张截图深入解析字节跳动的 Java 开发实力
    在与一位来自字节跳动的朋友交流时了解到,根据他们近期招聘Java工程师的经验,大多数候选人往往在工作3年后会遇到一个难以跨越的瓶颈期。这是因为在职业生涯的这个阶段,许多工程师的技术深度和广度已经达到了一定的水平,但要进一步提升则需要更多的挑战和学习机会。字节跳动作为一家技术驱动的公司,通过严格的面试流程和实际项目经验,能够更好地评估候选人的技术水平和发展潜力。 ... [详细]
author-avatar
血狼2732_150
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有