JVM虚拟机——JVM调优和性能优化

JVM调优,并不能显著的提高系统性能,JVM调优主要调的是稳定。如果系统出现了频繁的垃圾回收,这个时候系统是不稳定的,所以需要JVM调优。

GC调优

GC调优原则

  • 大多数Java应用不需要GC调优;
  • 大部分需要GC调优的,不是参数问题,而是代码问题;
  • GC调优是最后的手段;

目的

  • GC的时间够少;
  • GC的次数够少。

PS:如果满足以下指标,一般不需要进行GC调优:

  • Minor GC执行时间不到50ms;
  • Minor GC执行不频繁,约10s一次;
  • Full GC执行时间不到1s;
  • Full GC执行频率不频繁,不低于10min一次。

调优步骤

  • 监控GC状态:使用各种JVM工具,查看当前日志,分析当前JVM参数设置,分析当前堆内存快照和GC日志,根据实际的内存区域划分和GC执行时间,觉得是否进行优化;
  • 分析结果,判断是否需要优化:如果各项参数设置合理,系统没有超时日志出现,GC频率不高,GC耗时不高,那么没有必要进行GC优化;
  • 调整GC类型和内存分配:如果内存分配过大或过小,或者采用的GC收集器比较慢,则应该优先调整这些参数,并且找几台机器进行beta,比较优化过的机器和没有优化过的机器的性能对比,有针对性的做出最后选择;
  • 不断的分析和调整:通过不断试验,分析并找到最合适的参数;
  • 全面应用参数:找到最合适的参数后,将这些参数应用到所有服务器,并进行后续跟踪。
    PS:阅读GC日志时,主要关注MinorGC和FullGC 的回收效率(回收前大小和回收比较)、回收的时间。

策略

新生代大小的选择

1.响应时间优先的应用:尽可能设大,直到接近系统的最低响应时间限制(根据实际情况选择)。在此种情况下,新生代收集发生的频率也是最小的。同时,减少到达老年代的对象;
2.吞吐量优先的应用:尽可能的设置大,可能到达Gbit的程度。因为对响应时间没有要求,垃圾收集可以并行进行,一般适合8CPU以上的应用;
PS:避免设置过小,当新生代设置过小时会导致:1、MinorGC次数更加频繁 。2、可能导致MinorGC对象直接进入老年代,如果此时老年代满了,会触发FullGC。

老年代大小的选择

响应时间优先的应用:老年代使用并发收集器,所以其大小需要小心设置,一般要考虑并发会话率和会话持续时间等一些参数。如果堆设置小了,可以会造成内存碎片,高回收频率以及应用暂停而使用传统的标记清除方式;如果堆大了,则需要较长的收集时间。最优化的方案,一般需要参考以下数据获得:
并发垃圾收集信息、持久代并发收集次数、传统GC信息、花在新生代和老年代回收上的时间比例。

吞吐量优先的应用:一般吞吐量优先的应用都有一个很大的新生代和一个较小的老年代。原因是:这样可以尽可能回收掉大部分短期对象,减少中期的对象,而老年代尽存放长期存活对象。
PS:GC调优是个很复杂、很细致的过程,要根据实际情况调整,不同的机器、不同的应用、不同的性能要求调优的手段都是不同的。

性能优化

一个web应用不是一个孤立的个体,它是一个系统的部分,系统中的每一部分都会影响整个系统的性能。

常用的性能评价指标

  • 响应时间:提交请求和返回该请求的响应之间使用的时间,一般比较关注平均响应时间。
  • 并发数:同一时刻,对服务器有实际交互的请求数。估算并发数:比如1000个同时在线用户数,可以估计并发数在5%到15%之间,也就是同时并发数在50~150之间。
  • 吞吐量:对单位时间内完成的工作量(请求)的量度。

三者关系:
可以理解为高速公路的通行状况: 吞吐量是每天通过收费站的车辆数目(可以换算成收费站收取的高速费);
并发数是高速公路上的正在行驶的车辆数目; 响应时间是车速。
车辆很少时,车速很快。但是收到的高速费也相应较少;随着高速公路上车辆数目的增多,车速略受影响,但是收到的高速费增加很快;
随着车辆的继续增加,车速变得越来越慢,高速公路越来越堵,收费不增反降;
如果车流量继续增加,超过某个极限后,任何偶然因素都会导致高速全部瘫痪,车走不动,当然高速费也收不着(资源耗尽)。

性能优化思路

  • 避免过早优化:不应该把大量的时间耗费在小的性能改进上,过早考虑优化是所有噩梦的根源。所以,我们应该编写清晰,直接,易读和易理解的代码,真正的优化应该留到以后,等到性能分析表明优化措施有巨大的收益时再进行。
  • 进行系统性能测试:所有的性能调优,都有应该建立在性能测试的基础上,直觉很重要,但是要通过测试求证;
  • 寻找系统瓶颈,分而治之,逐步优化:性能测试后,对整个请求经历的各个环节进行分析,排查出现性能瓶颈的地方,定位问题,分析影响性能的的主要因素是什么?内存、磁盘IO、网络、CPU,还是代码问题?架构设计不足?或者确实是系统资源不足?

前端优化常用手段

  • 减少请求数:合并CSS,Js,图片,生产服务器提供的all的js文件,http中的keep-alive(http1.1中默认开启);
  • 使用客户端缓冲:静态资源文件(css、图标等)缓存在浏览器中,有关的属性Cache-Control(相对时间)和Expires。如果文件发生了变化,需要更新,则通过改变文件名来解决。
  • 启用压缩:zip,压缩率最多可达80%。减少了网络传输量,但会给浏览器和服务器带来性能的压力,需要权衡使用。
  • 资源文件加载顺序:CSS放在页面最上面,JS放在最下面。这样页面的体验才会比较好。浏览器会加载完CSS才会对页面进行渲染。JS只要加载后就会立刻执行。(有些JS可能执行时间比较长)。
  • 减少Cookie传输:Cookie包含在每次的请求和响应中,因此哪些数据写入cookie需要慎重考虑(静态资源不需要放入cookie)。
  • 友好的提示(非技术手段):有时候在前端给用户一个提示,就能收到良好的效果。毕竟用户需要的是不要不理他。
  • CDN加速:CDN,又称内容分发网络,本质是一个缓存,而且是将数据缓存在用户最近的地方。无法自行实现CDN的时候,可以根据经济实力考虑商用CDN服务。
  • 反向代理缓存:将静态资源文件缓存在反向代理服务器上,一般是Nginx。
  • WEB组件分离:将JS,CSS和图片文件放在不同的域名下,可以提高浏览器在下载web组件的并发数。因为浏览器在下载同一个域名的的数据存在并发数限制。

应用服务性能优化

网站性能优化第一定律:优先考虑使用缓存优化性能(缓存离用户越近越好)。

  • 缓存的基本原理和本质:缓存是将数据存在访问速度较高的介质中。可以减少数据访问的时间,同时避免重复计算。
  • 使用缓存的准则:频繁修改的数据,尽量不要缓存,读写比2:1以上才有缓存的价值(我们一般10:1才使用缓存)。缓存一定是热点数据。应用需要容忍一定时间的数据不一致。
    缓存可用性问题:一般通过热备或者集群来解决。
  • 分布式缓存:以集群的方式提供缓存服务,有两种实现:
    1、需要更新同步的分布式缓存,所有的服务器保存相同的缓存数据,带来的问题就是,缓存的数据量受限制,其次,数据要在所有的机器上同步,代价很大。
    2、每台机器只缓存一部分数据,然后通过一定的算法选择缓存服务器。常见的余数hash算法存在当有服务器上下线的时候,大量缓存数据重建的问题。所以提出了一致性哈希算法。

集群

可以很好的将用户的请求分配到多个机器处理,对总体性能有很大的提升。

异步

同步和异步,阻塞和非阻塞

同步和异步关注的是结果消息的通信机制
同步:同步的意思就是调用方需要主动等待结果的返回
异步:异步的意思就是不需要主动等待结果的返回,而是通过其他手段比如,状态通知,回调函数等。
阻塞和非阻塞主要关注的是等待结果返回调用方的状态
阻塞:是指结果返回之前,当前线程被挂起,不做任何事
非阻塞:是指结果在返回之前,线程可以做一些其他事,不会被挂起。

常见的异步手段
  • Servlet异步
  • 多线程
  • 消息队列

程序优化

  • 代码级别的优化:选择合适的数据结构;选择更优的算法;编写更少的代码。
  • 并发编程
  • 资源的复用:目的是减少开销很大的系统资源的创建和销毁,比如数据库连接,网络通信连接,线程资源等等。解决方法是:单例模式(Spring中的bean);池化技术。

存储性能优化

  • 尽量使用SSD
  • 定时清理数据或者按数据的性质分开存放
  • 结果集处理:用setFetchSize控制jdbc每次从数据库中返回多少数据。

你可能感兴趣的:(JVM虚拟机,JVM,性能优化,GC调优,虚拟机,系统分析)