jvm调优

-* 标准参数 如: -D<名称>=<值> 设置系统属性
-X 参数(非标准参数) 不同版本jdk可能不一样
-XX 参数(使用率较高) 主要用于jvm的调优和debug 一种是boolean类型(:+或者-属性名),一种是非boolean类型 -XX:+DisableExplicitGC 表示禁用手动调用gc操作 -XX:NewRatio=1 表示新生代和老年代的比值

常用非标参数
-Xms 设置初始 Java 堆大小
-Xmx 设置最大 Java 堆大小

-Xmx2048m:等价于-XX:MaxHeapSize,设置JVM最大堆内存为2048M。
-Xms512m:等价于-XX:InitialHeapSize,设置JVM初始堆内存为512M。
适当的调整jvm的内存大小,可以充分利用服务器资源,让程序跑的更快。

运行java命令时打印参数,需要添加-XX:+PrintFlagsFinal参数即可 打印出的参数有boolean类型和数字类型,值的操作符是=或:=,分别代表默认值和被修改的值。

通过jps 或者 jps -l 查看java进程名称及进程id
jinfo -flags <进程id> 查看正在运行的jvm参数
#查看某一参数的值,用法:jinfo -flag <参数名> <进程id>

jdk1.8和1.7的jvm内存模型比较起来,差别最大的地方是 1.7中的永久区被1.8的metaSpace元数据空间所代替,并且metaspace所占用的内存空间不在jvm内部了,而是在本地内存空间中

jstat命令进行查看堆内存使用情况
jstat -class 进程id 查看类加载统计
jstat -compiler 进程id 查看编译统计
jstat -gc 进程id 查看垃圾回收统计

jmap -heap 进程id 查看内存使用情况
jmap -histo 进程id 查看内存中对象数量及大小
jmap -dump:format=b,file=/tmp/dump.dat 6219 将内存的使用情况dump到文件中

jvisualVM.exe jdk bin目录下的图形化监测工具

Java代码的优化
1.尽可能使用局部变量,因为局部变量存在于栈中,当方法运行结束后局部变量将直接清除,不需要额外的垃圾回收
2.尽量减少对变量的重复计算,比如 遍历list可以先将list.size()在循环外获取,循环时直接用获取的结果,而不是每次循环都调用一下list.size() for (int i = 0; i < list.size(); i++){…}
3.尽量采用懒加载的策略,在需要的时候再创建对象
4.不要创建一些不使用的对象以及导入一些不使用的类
5.程序运行过程中避免使用反射,反射功能强大,但效率不高。 如果使用反射,尽量在程序启动时一次性将需要的对象用反射创建出来。
6.使用数据库连接池和线程池
7.容器初始化时尽可能指定长度,因为集合的长度不足,扩容会导致性能的损耗
8. ArrayList查找快,linkedList增删快 遍历map使用entry
9.String 尽量少用正则表达式
10.资源使用完毕一定要关闭,并且分开关闭
11. javap -v java字节码文件 可以查看字节码文件的内容,通过探究底层执行情况来比较代码的执行效率

对于tomcat的优化,主要是从2个方面入手,一是,tomcat自身的配置,另一个是tomcat所运行的jvm虚拟机的调优。
Tomcat优化:
1.禁用ajp连接
AJP(Apache JServer Protocol) AJPv13协议是面向包的。WEB服务器和Servlet容器通过TCP连接来交互;为了
节省SOCKET创建的昂贵代价,WEB服务器会尝试维护一个永久TCP连接到servlet容器,并且在多个请求和响应周
期过程会重用连接。
我们一般是使用Nginx+tomcat的架构,所以用不着AJP协议,所以把AJP连接器禁用。
修改conf下的server.xml文件,将AJP服务禁用掉即可。注释掉如下配置

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> 

2.使用线程池
对最大线程数,初始线程数及等待队列长度这些参数进行调整,吞吐量和响应时间做一个均衡

在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属性指向上面的执行器-->
<Connector executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />

3.选择合适的运行模式,Tomcat8及以上选择nio2

tomcat的运行模式有3种:

  1. bio 默认的模式,性能非常低下,没有经过任何优化处理和支持.
  2. nio nio(new I/O),是Java SE 1.4及后续版本提供的一种新的I/O操作方式(即java.nio包及其子包)。Java nio是
    一个基于缓冲区、并能提供非阻塞I/O操作的Java API,因此nio也被看成是non-blocking I/O的缩写。它拥有
    比传统I/O操作(bio)更好的并发运行性能。
  3. apr 安装起来最困难,但是从操作系统级别来解决异步的IO问题,大幅度的提高性能.
    推荐使用nio,不过,在tomcat8中有最新的nio2,速度更快,建议使用nio2.
    设置nio2:
<Connector executor="tomcatThreadPool" port="8080"
protocol="org.apache.coyote.http11.Http11Nio2Protocol"
connectionTimeout="20000"
redirectPort="8443" />

4.对jvm参数进行调优

JAVA_OPTS="-XX:+UseG1GC -Xms64m -Xmx512m -
XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -
Xloggc:…/logs/gc.log"

查看gc日志文件 对jvm参数进行调优 使用G1垃圾收集器
将gc.log文件上传到gceasy.io查看gc中是否存在问题,对jvm参数进行调优 比如 fullGC次数过多说明 堆内存大小设置不合理需增加等

垃圾回收机制

为什么要进行垃圾回收?
程序的运行必然需要申请内存资源,无效的对象如果不及时处理就会一直占有内存资源,最终将导致内存溢
出,所以对内存资源的管理是非常重要了。

常见垃圾回收算法
1.引用计数法 每个对象都有一个引用计数器,被引用,计数器就加1,引用失效就减一。计数器为0则是无效对象
优点; 实时性高,对象的引用为0立即回收,不需等待。 计数器更新只影响当前对象,不影响其它对象。 内存申请失败直接报内存溢出
缺点:每次对象的引用变化都需更新计数器,有一些时间开销。 浪费cpu资源,即使内存足够仍在运行时进行计数器的统计。 无法解决循环引用的问题(最大问题)

2.标记清除算法:
是将垃圾回收分为2个阶段,分别是标记和清除。
标记:从根节点开始标记引用的对象。
清除:未被标记引用的对象就是垃圾对象,可以被清理。
最大的问题是:内存空间碎片化,效率低(标记和清除都需要遍历所有对象)

3.标记压缩算法:
标记压缩算法是在标记清除算法的基础之上,做了优化改进的算法。和标记清除算法一样,也是从根节点开始,对对象的引用进行标记,在清理阶段,并不是简单的清理未标记的对象,而是将存活的对象压缩到内存的一端,然后清理边界以外的垃圾,从而解决了碎片化的问题。不适用于垃圾对象比较多的场景
最大问题:效率低(标记和清除都需要遍历所有对象,压缩也增加了处理时间)

4.复制算法:
复制算法的核心就是,将原有的内存空间一分为二,每次只用其中的一块,在垃圾回收时,将正在使用的对象复制到另一个内存空间中,然后将该内存空间清空,交换两个内存的角色,完成垃圾的回收。
如果内存中的垃圾对象较多,需要复制的对象就较少,这种情况下适合使用该方式并且效率比较高,反之,则不适合。

5.分代算法: 根据回收对象的特点进行选择,在jvm中,年轻代适合使用复制算法,老年代适合使用标记清除或标记压缩算法。

垃圾收集器是对垃圾回收算法的具体实现,有串行垃圾收集器,并行垃圾收集器,并发垃圾收集器及G1垃圾收集器

串行垃圾收集器,是指使用单线程进行垃圾回收,垃圾回收时,只有一个线程在工作,并且java应用中的所有线程都要暂停,等待垃圾回收的完成。这种现象称之为STW(Stop-The-World)。对于交互性较强的应用而言,这种垃圾收集器是不能够接受的。一般在Javaweb应用中是不会采用该收集器的。

并行垃圾收集器采用了多线程,比串行垃圾收集器快一些但在垃圾收集时还是会暂停应用程序

CMS垃圾收集器,concurrent mark sweep 用于老年代的,并发标记收集器,在初始化标记和重新标记时需要stw,其它环节都可以和应用程序并发进行

G1垃圾收集器是在jdk1.7中正式使用的全新的垃圾收集器,目前是性能最好的垃圾收集器。它简化jvm性能调优,只要使用它并设置最大堆内存和最大停顿时间即可
G1垃圾收集器中分三种垃圾收集模式:youngGC FullGC mixedGC
G1垃圾收集器和其它垃圾收集器的最大区别在于,它取消了物理上的年轻代和老年代的划分,仍保留着逻辑上的年轻代和老年代,把堆内存空间划分成了多个区域 Region

G1垃圾收集器年轻代垃圾收集时消除了碎片空间,使内存空间变的连续。 同时专门为巨型对象设置了一个H区(其它收集器巨型对象是直接放入老年代的,对于使用次数较少的巨型对象,这样是不合适的)

Mixed GC 当越来越多的对象晋升到老年代old region时,为了避免堆内存被耗尽,虚拟机会触发一个混合的垃圾收集器,即
Mixed GC,该算法并不是一个Old GC,除了回收整个Young Region,还会回收一部分的Old Region

MixedGC什么时候触发? 由参数 -XX:InitiatingHeapOccupancyPercent=n 决定。默认:45%,该参数的意思是:
当老年代大小占整个堆大小百分比达到该阀值时触发。

G1收集器相关参数
-XX:+UseG1GC
使用 G1 垃圾收集器
-XX:MaxGCPauseMillis
设置期望达到的最大GC停顿时间指标(JVM会尽力实现,但不保证达到),默认值是 200 毫秒。
-XX:G1HeapRegionSize=n
设置的 G1 区域的大小。值是 2 的幂,范围是 1 MB 到 32 MB 之间。目标是根据最小的 Java 堆大小划
分出约 2048 个区域。
默认是堆内存的1/2000。
-XX:ParallelGCThreads=n
设置 STW 工作线程数的值。将 n 的值设置为逻辑处理器的数量。n 的值与逻辑处理器的数量相同,最多
为 8。
-XX:ConcGCThreads=n
设置并行标记的线程数。将 n 设置为并行垃圾回收线程数 (ParallelGCThreads) 的 1/4 左右。
-XX:InitiatingHeapOccupancyPercent=n
设置触发标记周期的 Java 堆占用率阈值。默认占用率是整个 Java 堆的 45%。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值