JVM优化 和 tomcat启动优化

JVM的复习: 看jvm的图形

在这里插入图片描述
在这里插入图片描述
GC是什么?
频繁收集Young区
较少收集Old区
基本不动Perm区

GC三大算法:
GC算法总体概述:
在这里插入图片描述
JVM在进行GC时,并非每次都对上面三个内存区域一起回收的,大部分时候回收的都是指新生代

GC按照回收的区域又分了两种类型,一种是普通GC(minor GC),一种是全局GC(major GC or Full GC),
普通GC(minor GC):只针对新生代区域的GC。
全局GC(major GC or Full GC):针对年老代的GC,偶尔伴随对新生代的GC以及对永久代的GC。

复制算法:MinorGC :年轻代中使用的是 MinorGC,这种GC算法采用的是复制算法(Copying)

年轻代中的GC,主要是复制算法
HotSpot JVM把年轻代分为了三部分:1个Eden区和2个Survivor区(分别叫from和to)。默认比例为8:1:1,一般情况下,新创建的对象都会被分配到Eden区(一些大对象特殊处理),这些对象经过第一次Minor GC后,如果仍然存活,将会被移到Survivor区。对象在Survivor区中每熬过一次Minor GC,年龄就会增加1岁,当它的年龄增加到一定程度时,就会被移动到年老代中。因为年轻代中的对象基本都是朝生夕死的(80%以上),所以在年轻代的垃圾回收算法使用的是复制算法,复制算法的基本思想就是将内存分为两块,每次只用其中一块,当这一块内存用完,就将还活着的对象复制到另外一块上面。复制算法不会产生内存碎片。

在GC开始的时候,对象只会存在于Eden区和名为“From”的Survivor区,Survivor区“To”是空的。紧接着进行GC,Eden区中所有存活的对象都会被复制到“To”,而在“From”区中,仍存活的对象会根据他们的年龄值来决定去向。年龄达到一定值(年龄阈值,可以通过-XX:MaxTenuringThreshold来设置)的对象会被移动到年老代中,没有达到阈值的对象会被复制到“To”区域。经过这次GC后,Eden区和From区已经被清空。这个时候,“From”和“To”会交换他们的角色,也就是新的“To”就是上次GC前的“From”,新的“From”就是上次GC前的“To”。不管怎样,都会保证名为To的Survivor区域是空的。Minor GC会一直重复这样的过程,直到“To”区被填满,“To”区被填满之后,会将所有对象移动到年老代中。
在这里插入图片描述

因为Eden区对象一般存活率较低,一般的,使用两块10%的内存作为空闲和活动区间,而另外80%的内存,则是用来给新建对象分配内存的。一旦发生GC,将10%的活动区间与另外80%中存活的对象转移到10%的空闲区间,接下来,将之前90%的内存全部释放,以此类推。

复制算法的缺点:
复制算法弥补了标记/清除算法中,内存布局混乱的缺点。不过与此同时,它的缺点也是相当明显的。
1、它浪费了一半的内存,这太要命了。
2、如果对象的存活率很高,我们可以极端一点,假设是100%存活,那么我们需要将所有对象都复制一遍,并将所有引用地址重置一遍。复制这一工作所花费的时间,在对象存活率达到一定程度时,将会变的不可忽视。 所以从以上描述不难看出,复制算法要想使用,最起码对象的存活率要非常低才行,而且最重要的是,我们必须要克服50%内存的浪费。

标记清除/标记整理算法:FullGC又叫MajorGC : 老年代一般是有标记清除或者标记清除与标记整理的混合实现
标记清除的原理图:
在这里插入图片描述
标记清除的缺点 :①效率比较低(递归与全堆对象遍历)而且在进行GC的时候,需要停止应用程序,这会导致用户的体验非常差劲。②这种方式清理出来的空闲是不连续的,并且是死亡对象也是随机出现在各个角落的,现在把他们清除后,内存的布局肯定会乱七八糟,为了应付这个,JVM又不得不维护一个内存的空闲列表,并且在分配数组对象的时候,寻找连续的内存空间有不好找

标记整理(Mark-Compact)的原理:
在这里插入图片描述

标记整理的算法 : 唯一的缺点就是效率不高,不进要标记多有存活对象,还要整理所有存活对象的引用地址,从效率上说,标记/整理算法要低于复制算法

小总结:
内存效率:复制算法>标记清除算法>标记整理算法(此处的效率只是简单的对比时间复杂度,实际情况不一定如此)。
内存整齐度:复制算法=标记整理算法>标记清除算法。
内存利用率:标记整理算法=标记清除算法>复制算法。

年轻代(Young Gen)
年轻代特点是区域相对老年代较小,对像存活率低。
这种情况复制算法的回收整理,速度是最快的。复制算法的效率只和当前存活对像大小有关,因而很适用于年轻代的回收。而复制算法内存利用率不高的问题,通过hotspot中的两个survivor的设计得到缓解。

老年代(Tenure Gen)
老年代的特点是区域较大,对像存活率高。

这种情况,存在大量存活率高的对像,复制算法明显变得不合适。一般是由标记清除或者是标记清除与标记整理的混合实现。
Mark阶段的开销与存活对像的数量成正比,这点上说来,对于老年代,标记清除或者标记整理有一些不符,但可以通过多核/线程利用,对并发、并行的形式提标记效率。
Sweep阶段的开销与所管理区域的大小形正相关,但Sweep“就地处决”的特点,回收的过程没有对像的移动。使其相对其它有对像移动步骤的回收算法,仍然是效率最好的。但是需要解决内存碎片问题。

Compact阶段的开销与存活对像的数据成开比,如上一条所描述,对于大量对像的移动是很大开销的,做为老年代的第一选择并不合适。

基于上面的考虑,老年代一般是由标记清除或者是标记清除与标记整理的混合实现。以hotspot中的CMS回收器为例,CMS是基于Mark-Sweep实现的,对于对像的回收效率很高,而对于碎片问题,CMS采用基于Mark-Compact算法的Serial Old回收器做为补偿措施:当内存回收不佳(碎片导致的Concurrent Mode Failure时),将采用Serial Old执行Full GC以达到对老年代内存的整理。

Tomcat之启动优化:
大概在catalina.sh文件的97行
在这里插入图片描述

修改内容如下:
在这里插入图片描述

export JAVA_OPTS="-server -Xms1600M -Xmx1600M -Xss512k -XX:+AggressiveOpts -XX:+UseBiasedLocking -XX:PermSize=128M -XX:MaxPermSize=256M -XX:+DisableExplicitGC -XX:MaxTenuringThreshold=31 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -Djava.awt.headless=true"

查看是否生效: ps -ef |grep tomcat
jmap -heap 进程号(tomcat的进程号);
显示的内容:
在这里插入图片描述

参数逐项说明:
1.-server

-server 启用jdk 的 server 版;

只要你的tomcat是运行在生产环境中的,这个参数必须添加
因为tomcat默认是以一种叫java –client的模式来运行的,server即意味着你的tomcat是以真实的production的模式在运行的,这也就意味着你的tomcat以server模式运行时将拥有:
更大、更高的并发处理能力,更快更强捷的JVM垃圾回收机制,可以获得更多的负载与吞吐量......

2.-Xms -Xmx

-Xms 初始堆大小;其初始空间(即-Xms)是物理内存的1/64,

-Xmx 最大堆大小; 最大空间(-Xmx)是物理内存的1/4。

-Xmn 年轻代堆内存大小,此处是(eden+ 2 survivor space),默认为物理内存的1/64.

可以利用JVM提供的-Xmn -Xms -Xmx等选项,

要加“m”说明是MB,否则就是KB了,在启动tomcat时会报内存不足。

把Xms与Xmx两个值设成一样是最优的做法

WHY?
==================================================

一般设置-Xms、-Xmx相等以避免在每次GC后调整堆的大小。因为默认空余堆内存小于40%

时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70%时,JVM会减少堆直到-Xms的

最小限制。

3.-Xss

是指设定每个线程的栈大小。一般设置不超过1M,要不然容易出现out of memory

4.-XX:+AggressiveOpts

自带魔法属性,从单词可以看出,积极的、生猛的,也即可以将最新版的JDK优化后的新特性自动注入

5.-XX:+UseBiasedLocking

启用一个优化了的线程锁,对于高并发访问很重要 ,太多的请求忙不过来它自动优化,对于各自长短不一的请求,出现的阻塞、排队现象,他自己优化

6.-XX:PermSize -XX:MacPermSize

-XX:PermSize设置Perm区的初始大小,默认是物理内存的1/64;
在数据量的很大的文件导出时,一定要把这两个值设置上,否则会出现内存溢出的错误。
-XX:MaxPermSize设置Perm区的最大值,默认是32M,建议达到物理内存的1/4。
存放的都是jvm初始化时加载器加载的一些类型信息(包括类信息、常量、静态变量等),这些信息的生存周期比较长,GC不会在主程序运行期对PermGen Space进行清理,所以如果你的应用中有很多CLASS的话,就很可能出现PermGen Space错误。
上述两个参数值存在于jdk1.7之前,1.8后就没有了。

7.-XX:MaxNewSize

-XX:MaxNewSize 设置最大的年轻代大小,默认是16M
-XX:NewSize 设置年轻代大小

8.-XX:+DisableExplicitGC

在程序代码中不允许有显示的调用”System.gc()”,避免内存的大起大落
忽略手动调用GC的代码使得 System.gc()的调用就会变成一个空调用,完全不会触发任何GC

9.-XX:MaxTenuringThreshold

-XX:MaxTenuringThreshold — 设置对象在新生代中存活的次数,设置垃圾最大年龄
1 如果设置为零的话,则年轻代对象不经过Survivor区直接进入年老代。对于年老代比较多的应用,可以提高效率。

2 如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概率。

这个值的设置是根据本地监控后得到的一个理想的值,不能一概而论原搬照抄。

默认为:15。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概论。

10.-XX:+UseConcMarkSweepGC

使用CMS内存收集。即CMS gc,这一特性只有jdk1.5即后续版本才具有的功能,它使用的是gc估算触发和heap占用触发。

我们知道频频繁的GC会造面JVM的大起大落从而影响到系统的效率,因此使用了CMS GC后可以在GC次数增多的情况下,每次GC的响应时间却很短,比如说使用了CMS GC后经过jprofiler的观察,GC被触发次数非常多,而每次GC耗时仅为几毫秒

添加该参数表示启动并发标识-清理(Mark-Sweep)回收器(CMS)

11.-XX:+UseParNewGC

设置年轻代为并行收集,对年轻代采用多线程并行回收,这样收得快

12.-XX:+CMSParallelRemarkEnabled

在使用UseParNewGC 的情况下, 尽量减少mark 的时间,降低标记停顿

13.-XX:+UseCMSCompactAtFullCollection

在使用concurrent gc 的情况下, 防止 memoryfragmention,
对live object 进行整理, 使 memory 碎片减少。

14.-XX:LargePageSizeInBytes

指定 Java heap的分页页面大小

15.-XX:+UseFastAccessorMethods

get,set 方法转成本地代码

16.-XX:+UseCMSInitiatingOccupancyOnly

指示只有在 old generation 在使用了初始化的比例后concurrent collector 启动收集

17.-Djava.awt.headless=true

这个参数一般我们都是放在最后使用的,这全参数的作用是这样的,有时我们会在我们的J2EE工程中使用一些图表工具如:jfreechart,用于在web网页输出GIF/JPG等流,

在winodws环境下,一般我们的app server在输出图形时不会碰到什么问题,

但是在linux/unix环境下经常会碰到一个exception导致你在winodws开发环境下图片显示的好好可是在linux/unix下却显示不出来,因此加上这个参数以免避这样的情况出现。

18.-XX:+PrintGCDetails

打印GC详情

Tomcat之并发优化:
位置:
/opt/tomcat7/conf下的server.xml文件中节点的配置优化,记得先备份;
出厂默认:
在这里插入图片描述
优化:
标准版:

<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="600"
minSpareThreads="100"
maxSpareThreads="500"
acceptCount="700"
connectionTimeout="20000"
redirectPort="8443" />

复杂版:

<Connector  port="8080"
protocol="HTTP/1.1"
URIEncoding="UTF-8"
minSpareThreads="25"
maxSpareThreads="75"
enableLookups="false"
disableUploadTimeout="true"
connectionTimeout="20000"
acceptCount="300"
maxThreads="300"
maxProcessors="1000"
minProcessors="5"
useURIValidationHack="false"
compression="on"
compressionMinSize="2048"
compressableMimeType="text/html,text/xml,text/JavaScript,text/css,text/plain"
redirectPort="8443"/>

坑爹情况:
在这里插入图片描述

1.URIEncoding=”UTF-8”
使得tomcat可以解析含有中文名的文件的url,在server.xml文件的Connector标签中增加URIEncoding="UTF-8"属性,解决中文参数乱码问题。
在这里插入图片描述

minSpareThreads

最小备用线程数,tomcat启动时的初始化的线程数,默认10

maxSpareThreads
enableLookups

如果希望调用request.getRemoteHost()进行DNS查询,以返回远程客户的实际主机名,将enableLookups设为true。

如果希望忽略DNS查询,仅仅返回IP地址,设为false(这样提高了性能)。

缺省情况下,DNS查询是使能的。

一句话:是否反查域名,取值为: true 或 false 。为了提高处理能力,应设置为 false

disableUploadTimeout

disableUploadTimeout="true",

类似于Apache中的keeyalive一样,是否需要tomcat容器单独设置上传时间限制,

这里是不用,还是使用标准的,不去给上传的附件单独做超时设置。

connectionTimeout

connectionTimeout:网络连接超时,单位毫秒。设置为 -1 表示永不超时

acceptCount

acceptCount是当线程数达到maxThreads后,后续请求会被放入一个等待队列,这个acceptCount是这个队列的大小,如果这个队列也满了,就直接refuse connection
一句话:acceptCount:当处理任务的线程数达到最大时,接受排队的请求个数,默认100

maxThreads

maxThreads:最大线程数,即同时处理的任务个数,默认值为200

Tomcat使用线程来处理接收的每个请求。这个值表示Tomcat可创建的最大的线程数,

 即最大并发数。
保守推荐:600---900

maxProcessors
minProcessors

在 Java中线程是程序运行时的路径,是在一个程序中与其它控制线程无关的、能够独立运行的代码段。它们共享相同的地址空间。多线程帮助程序员写出CPU最大利用率的高效程序,使空闲时间保持最低,从而接受更多的请求。

通常Windows是1000个左右,Linux是2000个左右。

useURIValidationHack

减少它对一些url的不必要的检查从而减省开销,为提高性能可以设置为false

compression

compression :设置是否开启GZip压缩
 HTTP 压缩可以大大提高浏览网站的速度,它的原理是,在客户端请求网页后,从服务器端将网页文件压缩,再下载到客户端,由客户端的浏览器负责解压缩并浏览。相对于普通的浏览过程HTML,CSS,Javascript , Text ,它可以节省40%左右的流量。更为重要的是,它可以对动态生成的,包括CGI、PHP , JSP , ASP , Servlet,SHTML等输出的网页也能进行压缩,压缩效率惊人。
compressionMinSize

compressionMinSize="2048" 启用压缩的输出内容大小,这里面默认为2KB

compressableMimeType

compressableMimeType:哪些类型需要压缩,默认是text/html,text/xml,text/plain

超时控制:

修改conf/web.xml配置文件,设置session-timeout的值(单位:分钟)
在这里插入图片描述

Tomcat的内存优化:
1.
查看%TOMCAT_HOME%\logs文件夹下,日志文件是否有内存溢出错误

错误提示:java.lang.OutOfMemoryError: Java heap space :

导致的原因:

Tomcat默认可以使用的内存为128MB,在较大型的应用项目中,这点内存是不够的,有可能导致系统无法运行。

常见的问题是报Tomcat内存溢出错误,Out of Memory(系统内存不足)的异常,从而导致客户端显示500错误,

一般调整Tomcat的使用内存即可解决此问题。

public static void main(String[] args)

  {

     System.out.println(Runtime.getRuntime().maxMemory()/1024/1024+" M");

     byte[] byteArray = new byte[1*1024*1024*650];

     System.out.println("#######3");

  }

windows环境下修改:

“%TOMCAT_HOME%\bin\catalina.bat”文件,在文件开头增加如下设置:

set JAVA_OPTS=-Dfile.encoding=UTF-8 -server -Xms1024m -Xmx2048m -XX:NewSize=512m -XX:MaxNewSize=1024m -XX:PermSize=256m -XX:MaxPermSize=256m -XX:MaxTenuringThreshold=10 -XX:NewRatio=2 -XX:+DisableExplicitGC

linux环境下修改:

“%TOMCAT_HOME%\bin\catalina.sh”文件,在文件开头增加如下设置:

JAVA_OPTS=-Xms2048m -Xmx2048m

错误提示:java.lang.OutOfMemoryError: PermGen space :

导致原因:

PermGen space的全称是Permanent Generation space,是指内存的永久保存区域,这块内存主要是被JVM存

放Class和Meta信息的,Class在被Loader时就会被放到PermGen space中,它和存放类实例(Instance)的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对PermGen space进行清理,所以如果你的应用中有很CLASS的话,就很可能出现PermGen space错误,这种错误常见在web服务器对JSP进行pre-compile的时候。如果你的WEB APP下都用了大量的第三方jar, 其大小超过了jvm默认的大小(4M)那么就会产生此错误信息了。
windows环境下修改:

“%TOMCAT_HOME%\bin\catalina.bat”文件,在文件开头增加如下设置:

set JAVA_OPTS=-Xms64m -Xmx256m -XX:PermSize=128M -XX:MaxNewSize=256m - XX:MaxPermSize=256m

linux环境下修改:

“%TOMCAT_HOME%\bin\catalina.sh”文件,在文件开头增加如下设置:

export JAVA_OPTS=-Xms256m -Xmx256m -XX:PermSize=128M -XX:MaxNewSize=256m XX:MaxPermSize=256m
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值