IDEA2019.2.1修改堆内存

背景

   网上有些文章说直接修改idea安装路径bin包下的idea64.exe.vmoptions文件;在这个文件中修改:-Xmx属性;当时是想修改堆内存希望减少idea启动时GC次数提高启动idea的速度;当年我也是搜到这些文章,按照文章的方法修改。但是修改完了,并不能感受到速度有什么提升。当时还以为是速度可能有些提升,但是提升的不明显。

   最近重读周志明的《深入理解Java虚拟机》其中介绍了一些关于内存分布和垃圾回收的知识。就想利用jdk的bin中的监控堆内存变化的工具jvisualvm.exe测试一下;想到要测试一下idea启动的时候堆内存的变化情况;下图是idea安装路径下的:idea64.exe.vmoptions的路径以及配置:

在这里插入图片描述


在这里插入图片描述

先启用监视工具:jvisualvm.exe,然后启动idea就可以监控到idea启动时堆内存的变化;

在这里插入图片描述
  橙色的曲线是堆最大内存的变化,可以看到是从100多兆(小于150M) -> 200多兆(小于250M) -> 300多兆 ->350多兆。这个结果根本不满足预期,因为我设置的堆内存是1024M足以满足idea启动时要占用的堆内存,不会发生堆的扩容。

  【概述】一栏看到了idea启动时实际使用的vm参数:
在这里插入图片描述
  这个vm参数值恰好与上面的结果刚好吻合;最小堆内存128m,最大512m;现在的问题是设置Xms,Xmx不起作用。

IDEA2019.2修改堆内存

  正在有些懵逼的情况下,恰好注意到了idea的启动文件:idea.bat(idea安装包bin目录下的idea.bat)在这个文件中,找到了idea 启动时要读取的vm配置文件的一个路径:idea64.exe.vmoptions的路径===》当前用户路径下的idea64.exe.vmoptions;

在这里插入图片描述
在这里插入图片描述
  这个文件里面的vm参数正是jvisualvm监控到的idea启动时使用的vm参数。

在这里插入图片描述

  到这里就很清晰了,idea启动时实际使用的vm参数,是从当前用户目录下的idea64.exe.vmoptions文件中获取虚拟机参数,而不是从安装路径下的idea64.exe.vmoptions文件中读取参数;因此要想修改的vm参数生效就需要修改当前用户下的idea64.exe.vmoptions文件;

修改测试


1.修改当前用户下的idea64.exe.vmoptions文件

在这里插入图片描述


  2.监控idea启动时堆内存的变化

在这里插入图片描述


  最大堆内存一直是512M,没有扩容符合预期。因为idea启动时最多存活对象300M左右;


idea.bat中读取vm配置文件的优先级

  在idea.bat中读取vm属性文件时的代码,上面提到一个读取vm配置属性的文件路径是读取当前用户目录下的idea64.exe.vmoptions;在idea.bat中读取vm属性配置的完整逻辑,如下:

/**idea.bat*/
...
...
...
SET VM_OPTIONS_FILE=%IDEA_VM_OPTIONS%
/* IDEA_VM_OPTIONS 在文件中没有设置这个变量是一个空值,会进入到if分支中被重新赋值*/
IF NOT EXIST "%VM_OPTIONS_FILE%" (
  :: Toolbox
  /**IDE_HOME=D:\IT_SOFT\IDE\ideaIU-2019.2.1\IntelliJ IDEA 2019.2.1 */
  /**%IDE_HOME%.vmoptions=D:\IT_SOFT\IDE\ideaIU-2019.2.1\IntelliJ IDEA 2019.2.1.vmoptions ,没有这个文件 */
  SET VM_OPTIONS_FILE=%IDE_HOME%.vmoptions
)
/**%IDE_HOME%.vmoptions:为空时,会进入到这个分支中找到当前用户下的idea64.exe.vmoptions文件配置vm的属性信息*/
IF NOT EXIST "%VM_OPTIONS_FILE%" (
  :: user-overridden
  SET VM_OPTIONS_FILE=%USERPROFILE%\.IntelliJIdea2019.2\config\idea%BITS%.exe.vmoptions
)
/**读取当前bin目录下的idea64.exe.vmoptions*/
IF NOT EXIST "%VM_OPTIONS_FILE%" (
  :: default, standard installation
  SET VM_OPTIONS_FILE=%IDE_BIN_DIR%\idea%BITS%.exe.vmoptions
)
/**读取当前bin\win目录下的idea64.exe.vmoptions,我这个版本bin目录下没有win目录。*/
IF NOT EXIST "%VM_OPTIONS_FILE%" (
  :: default, universal package
  SET VM_OPTIONS_FILE=%IDE_BIN_DIR%\win\idea%BITS%.exe.vmoptions
)
/**读取不到,打印错误信息*/
IF NOT EXIST "%VM_OPTIONS_FILE%" (
  ECHO ERROR: cannot find VM options file.
)

  选择配置vm的属性信息的最高优先级是获取IDEA_VM_OPTIONS变量配置的路径,在原idea.bat中没有配置IDEA_VM_OPTIONS变量因此读取不到。可以在idea.bat中配置IDEA_VM_OPTIONS变量,指定要读取的vm配置文件;直接指向到安装包路径下的文件:idea64.exe.vmoptions;

在这里插入图片描述
在这里插入图片描述
  这种修改idea.bat方式,只能使用idea.bat启动才会生效;如果用idea64.exe启动那么只有修改当前用户目录下的idea64.exe.vmoptions文件能生效。


调整堆内存减少GC次数

  将idea 的堆内存调整,最大最小值都是512M,不允许它扩容。用jvisualvm工具观察到它发生多次GC;

在这里插入图片描述

  可以从图中看到,堆内存使用在有些地方突然减少,这一定是发生了GC,收回了部分内存。在图中可以看到很多次内存突然减少,那就说明发生了多次GC;Visual GC中可以看到具体是那个部分发生了GC;
在这里插入图片描述
  堆内存是512M,默认配置下新生代和老年代的内存占比:oldGen : YoungGen = 2:1;可以算出来新生代内存(YoungGen) = 512M/3 = 170.6M;

  在新生代中Eden:survivor = 8:1(有2个survivor空间因此Eden占新生代的0.8)Eden内存 = 512/3*0.8=136.5M;(通过计算,发现与书中说的都对的上。)

  什么情况会发生GC呢?新生对象在Eden空间分配不到足够的内存(大对象可以直接进入老年代【多大的对象算是大对象也可以自定义】,不会发起GC),就会发起一次GC将剩余存活的对象放到一个survivor空间。在survoivor空间中的对象有2种情况可以进入到老年代中:

  • 存活年龄达到进入老年代的阈值MaxTenuringThreshold(可以设置);
  • 相同存活年龄的对象总和大于survivor空间的一半,年龄大于或等于该年龄的一半就直接进入老年代;

  从上图来看,Eden空间发生了28次GC,想要不发生GC有一种简单粗暴的方法;直接计算存活对象占用的内存,倒推出最大堆内存;新生代 + 老年代存活的对象大概占用了250M;Eden =250m;最大堆内存:250/0.8 * 3 =937m;设置最大堆内存=950M;

在这里插入图片描述

  还是有5次GC,仔细一想之前的计算根本就没有把GC回收的对象计算在内。想要不发生GC,那么Eden空间就必须容纳所有的对象;

在这里插入图片描述
  每一次GC都可能会死掉一些对象,因此最开始用存活的250M对象计算出的Eden空间根本就不能容纳所有对象。因为已经经过28次GC,已经过滤掉一些对象了;以950M的堆内存来看,5次GC大概过滤了多少对象:可以通过使用堆内存的曲线图大致估算一下:

在这里插入图片描述
  图中只标注了最后一次GC过滤掉的的对象大概有400m的对象;这5次GC一共加起来过滤的对象估计超过1G;如果想不发生GC,那么就要设置一个超大的堆内存了;经过多次实验设置Eden=2500m,最大堆内存:2500/0.8 * 2 =6250M只会发起一次GC(重新设置新生代,老年代的占比-XX:NewRatio=1),后来又试了多次,Eden=3G都还要发起一次GC

在这里插入图片描述

  这一次GC回收了2G左右的内存,后来稳定存活的对象大概是2.2G:2.6G ->700M ->2.2G;也就是说GC后大概新增了1.5G的对象;总对象大概就是:2.6 G + 1.5G = 4.1G;那么设置的堆内存就超过8G了;但是可以看到收益很小,从最开始的idea默认设置的堆内存(128~512)发生28次GC,到现在已经测试过的设置6250M的堆内存,只发生一次GC;节省下的GC时间= 28次GC用时- 1次GC用时 = 435 - 77 = 358ms=0.3s其实这点时间根本感觉不到。设置了超大的内存,但是节约的时间太小了,因此直接使用默认的堆内存设置就好了,不需要重新设置堆内存;那么启动的主要时间都花费到哪儿了呢?

在这里插入图片描述

  开机第一次启动idea花费时间特别长,其实主要就是花费在了编译,类加载上面了;其实GC长一些短一些反而感受不到,因为都是毫秒级;而前2项动则几十秒,或者一两分钟就让人感觉启动时间特别长了;在第一次启动idea之后,关闭重新打开idea会明显感觉到速度变快,也是因为idea在启动时编译,类加载时间变短(可以看前面几幅图,应该是idea做了优化);这也很符合我们平时使用时感受到的结果。把最大堆内存修改到1024M之后,关机-> 重新开机 -> 启动idea:编译,类加载速度也没有明显提升,还是感觉打开idea很慢;

在这里插入图片描述

  结论:修改idea的最大堆内存是可以节约GC的时间;如果打开的项目很小,GC时间原本只有几百毫秒这个时候修改堆内存实际就没有用。如果GC消耗时间很长,这个时候修改堆内存才有意义。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值