当前位置: 首页 > 后端技术 > Java

JVM调优与性能优化深入理解

时间:2023-04-01 19:56:23 Java

类别GC调优原理调优步骤GC调优目的实战推荐策略逃逸分析常用性能评估/测试指标响应时间并发数吞吐量关系常用高级性能优化方法避免过早优化进行系统性能测试寻找系统瓶颈,分而治之,逐步优化前端优化常用方法浏览器/AppCDN加速反向代理缓存WEB组件分离应用服务性能优化缓存集群异步多线程消息队列程序代码级并发编程资源的复用存储性能优化尝试使用SSD根据数据的性质定期清理数据或单独存储结果集处理总结:JVM调优的本质:对系统性能没有明显的提升,不是你可以调优,性能会提升几倍还是十次,JVM调优,主要调的是稳定性。如果你的系统有频繁的垃圾回收,此时系统不稳定,所以我们需要调优JVM,调整垃圾回收的频率。BacktoTopGCTuningPrinciples调优原则1.大部分java应用不需要GC调优2.GC调优大部分不是参数问题,而是代码问题3.实际使用中,分析GC优化代码远不止于此优化气相色谱参数;4.GC调优是不得已而为之。GC的目的是GC的时间足够小,GC的次数足够少。FullGC的周期足够长,时间合理。最好不要发生。注意:如果满足以下指标,一般不需要GC:MinorGC执行时间小于50ms;MinorGC的执行时间不频繁,大约10秒一次;FullGC执行时间小于1s;FullGC的执行频率不会太频繁。不少于10分钟;回到顶部GC调优及调优步骤日志分析1、监控GC状态使用各种JVM工具查看当前日志,分析当前JVM参数设置,分析当前堆内存快照和gc日志,根据实际情况各区内存划分和GC执行时间,考虑是否优化;2、分析结果,判断是否需要优化。如果参数设置合理,系统没有超时日志,GC频率不高,GC耗时不高,那么就没有必要进行GC优化;如果GC时间超过1-3秒,或者GC频繁,必须进行优化;3、调整GC类型和内存分配如果内存分配太大或太小,或者使用的GC收集器比较慢,应该优先调整这些参数,先找一台或几台机器进行测试,然后比较优化后的机器和未优化的机器的性能,并做出有针对性的最终选择;4.持续分析和调整通过不断的试错,分析找到最合适的参数5,全面应用参数如果找到最合适的参数,将这些参数应用到所有服务器,并跟进。阅读GC日志主要关注MinorGC和FullGC的回收效率(回收前和回收前大小对比),以及回收时间。-XX:+UseSerialGC以参数-Xms5m-Xmx5m-XX:+PrintGCDetails-XX:+UseSerialGC为例:DefNew:1855K->1855K(1856K),0.0000148secs4671KDefNew指定收集器类型,显示收集器发生在新一代。1855K->1855K(1856K)表示新生代回收前占用1855K,回收后占用1855K。新生代的大小为1856K。0.0000148秒表示年轻代回收需要时间。tenured表示收集发生在老年代2815K->4095K(4096K),0.0134819secs:意义同新生代的最后4671K表示堆的大小。-XX:+UseParNewGC收集器参数变为-XX:+UseParNewGC,日志变为:ParNew:1856K->1856K(1856K),0.0000107secs收集器参数变为-XX:+UseParallelGCorUseParallelOldGC,日志变为:[PSYoungGen:1024K->1022K(1536K)][ParOldGen:3783K->3782K(4096K)]4807K->4804K(5632K),-XX:+UseConcMarkSweepGCCMS收集器和G1收集器会有明显的相关词-XX:+UseG1GCGC调优实战项目开始GC优化1、打开日志分析-XX:+PrintGCDetails发现有包括FullGC2在内的多次GC,调整Metadata空间-XX:MetaspaceSize=64m减少FullGC3,减少Minorgc的次数,增加参数-Xms500mGC为reduceto4times4.减少Minorgc的次数,调整参数-Xms1000mGC为2次GC,不需要调整这么大的size,浪费资源项目运行GC优化使用jmeter访问三个接口在同时对index、time、noblemetal使用40个线程,循环2500次进行压力测试,观察并发变化jmeter聚合报告参数说明:1.使用单线程GC-XX:+UseSerialGC2.使用多线程GC-XX:+UseParNewGC多线程的吞吐量有一定的提升3.使用CMS-XX:+UseConcMarkSweepGCCMS使用并发收集,所以STW的时间更短小,吞吐量相比单线程有提升,并且最大请求时间MAX显着减少。4、在吞吐量最大的地方使用G1-XX:+UseG1GCG1,最大请求时间MAX下降明显。一行代码导致频繁GC,吞吐量下降很快。推荐策略新生代的大小选择响应时间优先的应用:尽量设置大,直到接近系统的最小响应时间限制(根据实际情况选择)。在这种情况下,新生代的分代收集频率也是最小的。同时,减少到达老年代的对象个数。吞吐量优先级的应用:设置的越大越好,可能达到Gbit级别。因为对响应时间没有要求,可以并行进行垃圾回收,一般适用于8个以上CPU的应用。避免设置得太小。当新生代设置过小,会导致:1.MinorGC次数会比较频繁2.可能导致MinorGC对象直接进入老年代。如果此时老年代满了,就会触发FullGC。Oldagesize选择响应时间优先的应用:oldage使用并发收集器,所以需要谨慎设置它的大小。通常,应考虑一些参数,例如并发会话率和会话持续时间。如果heap设置小,可能会造成内存碎片,Recycling频率高,应用暂停使用传统的mark-and-sweep方式;如果堆很大,收集起来需要很长时间。最优解一般需要参考以下数据得到:并发垃圾收集信息、持久代并发收集数、传统GC信息、新生代和老年代收集时间占比。吞吐量优先的应用:一般情况下,吞吐量优先的应用,新生代比较大,老年代比较小。原因是这样可以尽可能回收大部分的短期对象,减少中期对象,而老年代GC调优是一个非常复杂和细致的过程,用于存储长期存活的对象。应根据实际情况进行调整。不同的机器,不同的应用,不同的性能需求,调优的方法也不一样,金先生也不能告诉你。所有,甚至jvm参数都是一样的。比如与性能相关的操作系统工具,以及与操作系统本身相关的所谓大页面机制,就需要大家平时去积累、观察、实践。King老师在这个话题上除了给大家讲了各种java虚拟机的基础知识和内部原理之外,还给大家讲了一个性能优化的基本思路和方向。回页首逃逸分析是JVM能做的最激进的优化,最好不要调整相关参数。n涉及的JVM参数:-XX:+DoEscapeAnalysis:启用逃逸分析(默认开启)-XX:+EliminateAllocations:标量替换(默认开启)-XX:+UseTLABlocalthreadallocationbuffer(默认开启)如果是逃逸分析如果对象可以分配在栈上,那么对象的生命周期就跟随线程,不需要垃圾回收。如果经常调用这个方法,性能可以有很大的提升。采用逃逸分析——对象分配在栈上:不逃逸分析——对象全部分配在堆上(触发频率GC,增加负担):返回顶部常用的性能评估/测试指标Web应用不是一个孤立的个体,它是系统的一部分,系统的每一个部分都会影响到整个系统的性能。Responsetime提交请求到请求返回响应所用的时间,一般比较关心平均响应时间。常见操作的响应时间列表:实际同时与服务器交互的并发请求数。与网站在线用户数的相关性:1000个同时在线用户,可以估算并发数在5%~15%之间,即同时并发数在50~150之间。吞吐量与单位时间内完成的工作(请求)量系统吞吐量与系统并发和响应时间的关系:理解为高速公路的交通状况:吞吐量是每天通过收费站的车辆数量(可以换算成高-收费站收取的速度费),并发数就是高速公路上的车辆数量,响应时间就是车辆的速度。车辆少的时候,速度很快。但收取的高速通行费相应少;随着高速公路上车辆数量的增加,车辆行驶速度受到轻微影响,但收取的高速通行费却迅速增加;随着车辆数量的不断增加,车速越来越慢,高速公路越来越拥堵,通行费不涨反降;如果车流量继续增加,超过一定限度后,任务的偶然因素会导致高速公路完全瘫痪。离开停车场(资源耗尽)。回页首常用的性能优化方法避免过早的优化您不应该在小的性能改进上花费大量时间。过早地考虑优化是所有噩梦的根源。因此,我们应该编写清晰、直接、可读和易懂的代码,真正的优化应该留到以后,当性能分析表明优化措施有巨大的好处时。但是过早的优化并不意味着我们可以随便写代码,但是我们还是要注意写出高效优雅的代码。执行系统性能测试所有的性能调整都应该基于性能测试。直觉很重要,但要用数据说话。可以推测,但必须通过测试来验证。寻找系统瓶颈,分而治之,逐步优化性能测试,分析整个请求体验的各个环节,检查性能瓶颈出现在哪里,定位问题,分析影响性能的主要因素有哪些?内存、磁盘IO、网络、CPU或代码问题?架构设计不够?还是确实缺少系统资源?回页首前端优化常用手段Browser/App减少请求数合并CSS、Js、图片、生产服务器提供的所有js文件在http中保持存活(在http1.1中默认开启)包括nginx使用客户端-sidebufferingstatic资源文件(css、icons等)缓存在浏览器中。如果相关属性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以上时缓存才有价值。缓存必须是热点数据。应用程序需要在一定时间内容忍数据不一致。缓存可用性问题一般通过热备或集群来解决。分布式缓存和一致性哈希以集群的形式提供缓存服务,有两种实现方式;1、分布式缓存需要更新同步。所有服务器都存储相同的缓存数据。问题是缓存的数据量受限,其次数据必须在所有机器上同步,这是非常昂贵的。2、每台机器只缓存部分数据,然后通过一定的算法选择缓存服务器。常见的余数哈希算法存在服务器下线时需要重建大量缓存数据的问题。因此提出了一致性哈希算法。Consistenthashing:首先求出服务器(节点)的hash值,配置在0到2的32次方的连续统上,然后用同样的方法求出存放数据的key的hash值,映射到同一个圆圈。然后它从数据映射到的位置顺时针方向查找,将数据保存到它找到的第一个服务器。如果超过232个都找不到服务器,则保存到第一个服务器。一致性哈希算法对于节点的增减只需要对环空间中的一小部分数据进行迁移,具有很好的容错性和可扩展性。数据倾斜:一致性哈希算法在服务节点过少时,容易因节点分布不均造成数据倾斜。这时候大量的数据会集中在节点A上,只有少量数据位于节点B上。为了解决这个数据倾斜问题,一致性哈希算法引入了虚拟节点机制,即为每个服务节点计算多个哈希值,在每个计算结果位置放置一个服务节点,称为虚拟节点。具体方法可以通过在服务器ip或者主机名后面加一个数字来实现。例如,可以为每个服务器计算三个虚拟节点,因此“节点A#1”、“节点A#2”、“节点A#3”、“节点B#1”、“节点B#2”、“NodeB#3”哈希值,从而形成6个虚拟节点:同时,数据定位算法不变,只是多了一个虚拟节点映射到实际节点的步骤,比如定位“NodeA#1”,"三个虚拟节点“NodeA#2”和“NodeA#3”的数据都位于NodeA上,解决了服务节点少时数据倾斜的问题。在实际应用中,虚拟的数量nodes通常设置为32个或更多,这样即使是几个服务节点也能实现相对均匀的数据分布。回页首集群可以将用户请求分发到多台机器上处理,大大提高了整体性能异步同步与异步,阻塞与非阻塞同步与异步关注结果消息的通信机制同步:Synchronization的意思是,调用者需要主动等待结果的返回。异步:异步是指不需要主动等待结果返回,而是通过状态通知、回调函数等其他方式。阻塞和非阻塞主要关注等待结果返回的状态返回给调用者。阻塞:表示当前线程在返回结果之前被挂起,不做任何事情。非阻塞:是指线程在返回结果之前可以做一些其他的事情。不会被暂停。1.同步阻塞:同步阻塞基本上是编程中最常见的模型。例如,你去商店买衣服。去了之后发现衣服都卖完了。然后你在店里等,期间什么都不做(包括看手机),等着商家进货,直到有货,这样效率很低。jdk中的BIO属于同步阻塞2.同步非阻塞:同步非阻塞在编程中可以抽象为一种轮询方式。当你到店后发现衣服卖完了,这时候你就不用再傻等了。可以去其他地方,比如奶茶店买杯水,但还是要时不时去店里问问老板新衣服到没。jdk中的NIO属于同步非阻塞3.异步阻塞:异步阻塞在编程中很少用到。有点像你写一个线程池,提交然后马上future.get(),所以线程其实还是挂着的。有点像你去商店买衣服,这时候你发现衣服不见了,你这时候给老板留个电话,说衣服到了你给我打电话,然后然后你就守着电话,等着他响。不要这样做。这个确实感觉有点傻,所以这个模式用的比较少。4、异步非阻塞:比如你去商店买衣服,衣服没有了,只需要告诉老板这是我的电话,等衣服到了再打电话。然后就可以随心所欲的玩了,也不用担心衣服什么时候到。衣服到了,电话一响就可以去买衣服了。jdk中的AIO是Servlet常用的异步手段,只有异步servlet3才有,支持的web容器在tomcat7、jetty8之后。多线程消息队列返回页首程序代码级别应用程序的性能最终取决于代码的编写方式。选择正确的数据结构选择ArrayList和LinkedList对我们的程序性能影响很大,为什么呢?因为ArrayList内部是作为一个数组来实现的,所以存在不断的扩充和数据复制。选择一个更好的算法比如如何判断一个数是否是n的幂*类描述:选择一个更好的算法*/publicclassBetterAlg{//如何判断一个数是否是n的幂publicstaticvoidmain(String[]args)抛出异常{intn=2;扫描仪扫描仪=新扫描仪(System.in);while(scanner.hasNext()){//控制台输入intinput=scanner.nextInt();while(true){if(input==n){System.out.println("是("+n+")的幂");休息;}if(input%2!=0){System.out.println("不是("+n+")的幂");休息;}else{输入=输入/2;}}//if((input&(input-1))==0){//System.out.println("是("+n+")的幂");//}else{//System.out.println("不是("+n+")的幂");//}}}编写更少的代码以获得同样正确的程序,小程序比大程序快,无论编程语言如何。多路复用并发编程资源的目的是减少昂贵的系统资源的创建和销毁,例如数据库连接、网络通信连接、线程资源等。Spring单例模式下的Bean池化技术返回顶部存储性能优化尝试使用SSD定期清理数据或者根据数据处理的性质单独存储结果集使用setFetchSize来控制jdbc每次从数据库返回多少数据。回页首总结:调优是一个非常复杂和细致的过程,需要根据实际情况进行调整。不同的机器,不同的应用,不同的性能需求,有不同的调优方法。没有放之四海而皆准的配置或公式。即使对于jvm参数也是如此。比如与性能相关的操作系统工具,以及与操作系统本身相关的所谓大页面机制,就需要大家平时去积累、观察、实践。本专题除了介绍各种java虚拟机的基础知识和内部原理外,还告诉大家一个性能优化的基本思路和方向。如果这篇文章对你有帮助,别忘了连打3个,点赞、转发、评论,我们下期再见!获取方式:点赞、评论、关闭~学习更多JAVA知识技能,关注并私信博主(666)