JVM性能调优实战:让你的IntelliJ Idea纵享丝滑

本文已被Github仓库收录 https://github.com/silently9527/JavaCore

前言

在前面整理了一篇关于JVM故障诊断和处理工具,考虑到大部分的Java程序员都使用的是IntelliJ Idea,本篇就使用工具来实战演练对IntelliJ Idea运行速度调优

调优前的运行状态

原始配置内容

要查询idea原始配置文件的路径可以在VisualVM中的概述中查看

原始配置内容:

-XX:ReservedCodeCacheSize=240m
-XX:+UseCompressedOops
-Dfile.encoding=UTF-8
-XX:SoftRefLRUPolicyMSPerMB=50
-ea
-Dsun.io.useCanonCaches=false
-Djava.net.preferIPv4Stack=true
-Djdk.http.auth.tunneling.disabledSchemes=""
-XX:+HeapDumpOnOutOfMemoryError
-XX:-OmitStackTraceInFastThrow

-XX:ErrorFile=$USER_HOME/java_error_in_idea_%p.log
-XX:HeapDumpPath=$USER_HOME/java_error_in_idea.hprof

-Xmx512m

打印启动时间插件开发

需要直观的看到优化前和优化后启动时间的变化,所以需要简单做一个Idea的插件开发,关于Idea插件开发的流程建议参考我以前的文章《IDEA插件:多线程文件下载插件开发》

JVM的启动时间到所有组件初始化完成后的时间就看做是IDEA的启动时间,代码如下

public class MyApplicationInitializedListener implements ApplicationInitializedListener {
  @Override
  public void componentsInitialized() {
    RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean();
    long startTime = bean.getStartTime();
    long costTime = System.currentTimeMillis() - startTime;

    Messages.showMessageDialog("毫秒:" + costTime, "启动耗时", Messages.getInformationIcon());
  }
}

plugin.xml中添加如下代码:

<extensions defaultExtensionNs="com.intellij">
  <applicationInitializedListener id="MyApplicationInitializedListener"
                  implementation="cn.silently9527.MyApplicationInitializedListener"/>
</extensions>

优化前的启动信息与时间消耗

根据VisualGC和IDEA启动插件收集到的信息:

  • IDEA启动耗时 15s 总共垃圾收集22次,耗时1.2s,其中新生代GC 17次,耗时324ms;
  • 老年代GC 5次,耗时953ms 加载类27526个,耗时 21s

按照这个数据来看也算是正常,15s 其实也在接受范围内,由于本文主要演示性能调优,所以需要测试能否在快一些

开始尝试优化

调整内存来控制垃圾回收频率

图上我们可以看出,启动参数指定的512m的内存被分配到新生代的只有169m,由于IDEA是我们开发常用的工具,平时的编译过程也需要足够的内存,所以我们需要先把总的内存扩大,这里我设置最大的内存 -Xmx1024m ,为了让JVM在GC期间不需要再浪费时间再动态计算扩容大小,同时也设置了 -Xms1024m

在启动的过程中Eden共发生了17次GC,为了减少新生代gc次数,我把新生代的内存大小设置成 -Xmn256m ;

重新启动之后查看VisualGC,新生代gc次数从 17次 降低到了 7次,耗时从 324ms 降低到了 152ms。

在调整内存前发生了5次Full GC,调整内存后的依然还是有4次Full GC,但是从两张图我们可以看出,老年代的空间还有很多剩余,是不应该发生Full GC的;考虑是否是代码中有地方手动调用 System.gc() 出发了Full GC,所以添加了参数 -XX:+DisableExplicitGC ,再次重新启动IDEA,结果很失望,依然还有4次Full GC;

再次仔细观察优化前的图,注意看 Last Cause: Metadata GC Threshold , 最后一次gc是应该Metaspace区域内存不够发生的GC,为了验证我们的猜想,打印出GC日志来看看。在 idea.vmoptions 中添加打印日志相关的参数:

-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-Xloggc:../gc.log

JVM的GC日志的主要参数包括如下几个:

  • -XX:+PrintGC 输出GC日志
  • -XX:+PrintGCDetails 输出GC的详细日志
  • -XX:+PrintGCTimeStamps 输出GC的时间戳(以基准时间的形式)
  • -XX:+PrintGCDateStamps 输出GC的时间戳(以日期的形式,如 2013-05-04T21:53:59.234+0800)
  • -XX:+PrintHeapAtGC 在进行GC的前后打印出堆的信息
  • -Xloggc:../logs/gc.log 日志文件的输出路径

重新启动idea,查看gc.log

其中 PSYoungGen: 表示新生代使用的ParallelScavenge垃圾收集器, 31416K->0K(181248K) 表示 gc前已使用的内存大小 -> gc后已使用内存大小(该区域的总内存大小)

从日志中我们看出每次Full GC都是因为 Metadata GC Threshold ,而Metaspace每次gc回收的内存几乎没有,仅仅是扩大了该区域的容量;找到了原因那就好办了,添加如下的参数调整Metaspace的大小:

-XX:MetaspaceSize=256m

再次重启Idea之后,发现Full GC没有了,心情很爽

测试打开大项目点击编译代码,发现自己的idea卡死了,查看VisualGC之后发现堆内存都还有空闲,只有Metaspace被全部占满了,所以是自己给的最大空间设置太小,所以直接去掉了 -XX:MaxMetaspaceSize=256m

选择垃圾收集器

从刚才的gc日志中,我们可以发现默认使用的是ParallelScavenge + Parallel Old垃圾收集器,这个组合注重的是吞吐量,这里我们尝试换一个注重低延时的垃圾收集器试一试

ParNew + CMS

idea.vmoptions 中添加如下配置:

-XX:+UseConcMarkSweepGC
-XX:+UseParNewGC

重启IDEA之后查看VisualGC

很尴尬,同样发生了6次gc, ParallelScavenge + Parallel Old 的组合耗时197ms,而 ParNew + CMS 的组合耗时379ms;虽然是这个结果,但是我们需要考虑当前只发生了MinorGC,如果发生FullGC了结果又会如何了,大家可以自己测试一下

G1

我们在换一个最新的G1垃圾回收器试试,在 idea.vmoptions 中添加如下配置:

-XX:+UseG1GC

这个结果好像也还是要慢一点点,自己多次测试过这两个垃圾回收器,虽然每次结果都不一样,相差不远,所以垃圾回收器可以自己选择,这里我们选择的是G1

类加载时间优化

根据之前的分析,idea启动加载类27526个,耗时 21s,这个我们有办法能优化一下吗?因为idea是常用的开发工具,经常很多人的使用,我们可以认为它的代码是安全的,是否符合当前虚拟机的要求,不会危害虚拟机的安全,所以我们使用参数 -Xverify:none 来禁用字节码的验证过程

重启IDEA

耗时下降到了11s,效果还是比较明显的

总结

做完了所有优化之后,经过多次重启测试,平均的启动时间下降到了11s,为了安慰我本次操作没有白辛苦,搞一张11s以下的图

我已经从零开始手写了简易版springmvc,以及编写了详细的说明文档,希望能够帮助伙伴们深入理解springmvc核心原理.

源码获取地址:我把开源的项目代码都已经放到了Git仓库,Github仓库地址:https://github.com/silently9527 ,码云仓库地址:https://gitee.com/silently9527

到此这篇关于JVM性能调优实战:让你的IntelliJ Idea纵享丝滑的文章就介绍到这了,更多相关JVM性能调优内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • JVM性能调优实现原理及配置

    1.JVM内存模型 总结:可以发现最明显的一个变化是元空间从虚拟机转移到了本地内存.默认情况下,元数据空间大小仅受限于本地内存, 这意味着以后不会因为永久代大小不够而抛出OOM异常了. jdk1.8以前,HotSpot VM将class和类的jar包数据存储在PermGen里, PermGen大小是固定的,而且项目之间无法公用公有的class,所以很容易碰到OOM异常.改成MateSpace后, 各个项目会共享同样的class空间.比如多个项目都引用了apache-common包, 在MateS

  • IDEA设置JVM运行参数的方法步骤

    前言 有时候我们需要在程序运行的时候对程序设置环境变量,恰巧我也遇到了这个问题,所以在此记录一下IDEA是如何设置环境变量的. 作用   -Dproperty=Value 该参数通常用于设置系统级全局变量值,如配置文件路径,保证该属性在程序中任何地方都可访问.当然,也可以通过在程序中使用System.setProperty进行设置. 注意: 1.如果-Dproperty=value的value中包含空格,可以将value使用引号引起来.例如:-Dmyname="hello world"

  • IntelliJ IDEA设置JVM运行参数的操作方法

    打开 IDEA 安装目录,看到有一个 bin 目录,其中有两个 vmoptions 文件,需针对不同的JDK进行配置: 32 位:idea.exe.vmoptions 64 位:idea64.exe.vmoptions -Xms512m -Xmx1024m -XX:MaxPermSize=512m -XX:ReservedCodeCacheSize=225m -XX:+UseConcMarkSweepGC -XX:SoftRefLRUPolicyMSPerMB=50 -ea -Dsun.io.u

  • JVM性能调优实战:让你的IntelliJ Idea纵享丝滑

    本文已被Github仓库收录 https://github.com/silently9527/JavaCore 前言 在前面整理了一篇关于JVM故障诊断和处理工具,考虑到大部分的Java程序员都使用的是IntelliJ Idea,本篇就使用工具来实战演练对IntelliJ Idea运行速度调优 调优前的运行状态 原始配置内容 要查询idea原始配置文件的路径可以在VisualVM中的概述中查看 原始配置内容: -XX:ReservedCodeCacheSize=240m -XX:+UseComp

  • GC调优实战之高分配速率High Allocation Rate

    高分配速率(High Allocation Rate) 分配速率(Allocation rate)表示单位时间内分配的内存量.通常使用 MB/sec作为单位, 也可以使用 PB/year 等. 分配速率过高就会严重影响程序的性能.在JVM中会导致巨大的GC开销. 如何测量分配速率? 指定JVM参数: -XX:+PrintGCDetails -XX:+PrintGCTimeStamps , 通过GC日志来计算分配速率. GC日志如下所示: 0.291: [GC (Allocation Failur

  • Java性能调优概述

    程序性能的主要表现点: 执行速度:程序的反映是否迅速,响应时间是否足够短 内存分配:内存分配是否合理,是否过多地消耗内存或者存在内存泄漏 启动时间:程序从运行到可以正常处理业务需要花费多少时间 负载承受能力:当系统压力上升时,系统的执行速度.响应时间的上升曲线是否平缓 衡量程序性能的主要指标: 执行时间:程序从运行到结束所使用的时间 CPU时间:函数或者线程占用CPU的时间 内存分配:程序在运行时占用内容的空间 磁盘吞吐量:描述I/O的使用情况 网络吞吐量:描述网络的使用情况 响应时间:系统对用

  • sqlserver性能调优经验总结

    相信不少的朋友,无论是做开发.架构的,还是DBA等,都经常听说"调优"这个词.说起"调优",可能会让很多技术人员心头激情澎湃,也可能会让很多人感觉苦恼.当然,也有很多人对此不屑一顾,因为并不是每个人接触到的项目都很大,也不是每个人做的项目都对性能要求很高. 在主流的企业级开发和互联网应用中,数据库的重要性是不言而喻的,而数据库的性能对于整个系统的性能而言也是至关重要的,这里无庸赘述. sqlserver的性能调优,其实是个很宽广的话题.坦白讲,想从概念到实践的完全讲

  • 十分简单易懂的Java应用程序性能调优技巧分享

    大多数开发人员理所当然地以为性能优化很复杂,需要大量的经验和知识.好吧,不能说这是完全错误的.优化应用程序以获得最佳性能不是一件容易的事情.但是,这并不意味着如果你不具备这些知识,就不能做任何事情.这里有11个易于遵循的建议和最佳实践可以帮助你创建一个性能良好的应用程序. 大部分建议是针对Java的.但也有若干建议是与语言无关的,可以应用于所有应用程序和编程语言.在讨论专门针对Java的性能调优技巧之前,让我们先来看看通用技巧. 1.在你知道必要之前不要优化 这可能是最重要的性能调整技巧之一.你

  • 分享Java性能调优的11个实用技巧

    大多数开发人员认为性能优化是个比较复杂的问题,需要大量的经验和知识.是的,这并不没有错.诚然,优化应用程序以获得最好的性能并不是一件容易的事情,但这并不意味着你在没有获得这些经验和知识之前就不能做任何事.下面有几个很容易遵循的建议和最佳实践能够帮你创建一个性能良好的应用程序. 这些建议中的大多数都是基于Java的,但是也不一定,也有一些是可以应用于所有的应用程序和编程语言的.在我们分享基于Java的性能调优技巧之前,让我们先讨论一下这些通用的性能调优技巧. 1.在必要之前,先不要优化 这可能是最

  • SpringBoot JVM参数调优方式

    目录 SpringBoot JVM参数调优 各种参数 SpringBoot jar包启动设置JVM参数 配置初始化堆和最大堆的大小 SpringBoot JVM参数调优 各种参数 参数名称 含义 默认值 说明 -Xms 初始堆大小 物理内存的1/64(<1GB) 默认(MinHeapFreeRatio参数可以调整)空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制. -Xmx 最大堆大小 物理内存的1/4(<1GB) 默认(MaxHeapFreeRatio参数可以调整)空余堆内存大

  • GC调优实战之过早提升Premature Promotion

    目录 过早提升(Premature Promotion) 如何测量提升速率 提升速率的意义 示例 过早提升的影响 解决方案 过早提升(Premature Promotion) 提升速率(promotion rate), 用于衡量单位时间内从年轻代提升到老年代的数据量.一般使用 MB/sec 作为单位, 和分配速率类似. JVM会将长时间存活的对象从年轻代提升到老年代.根据分代假设, 可能存在一种情况, 老年代中不仅有存活时间长的对象,也可能有存活时间短的对象.这就是过早提升:对象存活时间还不够长

  • 千万级用户系统SQL调优实战分享

    用户日活百万级,注册用户千万级,而且若还没有进行分库分表,则该DB里的用户表可能就一张,单表上千万的用户数据. 某系统专门通过各种条件筛选大量用户,接着对那些用户去推送一些消息: 一些促销活动消息 让你办会员卡的消息 告诉你有一个特价商品的消息 通过一些条件筛选出大量用户,针对这些用户做推送,该过程较耗时-筛选用户过程. 用户日活百万级,注册用户千万级,而且若还没有进行分库分表,则该DB里的用户表可能就一张,单表上千万的用户数据. 对运营系统筛选用户的SQL: SELECT id, name 

随机推荐