怎样通过优化JVM参数配置从而提升性能

怎样通过优化JVM参数配置从而提升性能?针对这个问题,今天小编总结这篇有关的文章,希望能帮助更多想解决这个问题的朋友找到更加简单易行的办法。

1内存构成

年老代年轻代
EdenS1S2

如图,Java虚拟机的内存,也就是常说的堆,主要分为年轻代和年老代两个部分。年轻代存放生命周期很短的对象,年老代存放长期存活的对象,例如,经过几次垃圾回收之后,一个对象仍然存活,那么这个对象就会从年轻代进入年老代。

年轻代又分为3个区:伊甸园,幸存者1,幸存者2(以下简称伊甸园,S1, S2) .Eden存放新对象,S1和S2交替使用,用来存放垃圾回收时存活的对象。

2回收策略

Java虚拟机的垃圾回收策略很复杂,这里我们只关心最影响性能的几种情况。

Java的垃圾回收分为两种:完整GC和GC,前者是对年老代的回收,一般会很慢,后者是针对年轻代的回收,这个很快。我们调优的目标就是尽量避免频繁的完整GC。那么什么情况会触发完整GC呢?上面说了,新对象会存放在伊甸园区,而当伊甸园区满了的时候就会触发小GC,此时伊甸园区的垃圾对象会被清除,而存活下来的有用对象则会往S1或S2区复制,从而完成一次回收过程。在这个过程中,如果S1或S2区装不下伊甸园里幸存的对象了,就会把幸存的对象保存到年老代,而如果年老代也没有空间了,就会触发完整GC。

简述就是,幸存者区装不下年轻代的幸存对象时,会造成年老代的增长,随着年老代不断增长,完整GC必然会被触发。

3 sortx时的内存使用

我们知道sortx函数有个参数n, n是缓冲区条数,表示每次从游标中取出来的记录条数。那么n取什么值最合适呢?

显然n不能取值太大,否则会造成内存溢出,根本无法使用。

那么再不断尝试取小点,经过几次尝试后,会发现可以用了,不会溢出了。但这时不一定是最优取值,如果n取值占用的内存大于伊甸园,且正好把年老代占用的差不多了,则每次取出的数据都会送进年老代,等到下一次取数的时候,就触发完整的GC,而这种频繁触发是最耗时的。

所以,从Java的分配和回收策略来看,最理想的情况是,n的取值占用的内存,略小于伊甸园的大小。这是因为sortx这类运算的特点是“取出即用,用完就扔”,很少有对象会常驻内存。

那么如何知道伊甸园区的大小然后估算n呢?

4内存分配

在IDE的启动配置里可以看的到,参数- xmx用来指定分配给Java的堆内存的大小,例如-Xmx10g就表示分配了10 g内存给Java。那么Java如何把这10 g分配给这几个区呢?

默认的情况下,各区比例大概是这样的:

年轻代:年老代=3:7

伊甸园:S1, S2=8: 1: 1

,,,,,有了比例,很容易算出来各区大小,年老代占7 g,年轻代占3 g,其中伊甸园占2.4 g, S1和S2各占0.3 g。据说这个默认比例是jdk的开发人员统计得出的,认为在大部分应用中,幸存对象占全部对象的1/10。然而这个比例不一定适合所有情形,至少在sortx时就不太合适。

5结论

n的取值原则:使用sortx时,在不溢出的前提下,n的取值并不是越大越好,而是(根据伊甸园大小)估算一个合适的值,这个值不引起频繁完整GC。

验证n值是否合适的办法如下:

1添加参数- xx: + PrintGC。

2运行sortx .

3观察控制台,如果频繁出现[完整GC(分配失败)……]信息则调小n,重试。

4如果只出现很多GC(分配失败)[……]信息,则认为n的值是合适的。

5如果出现很多GC(分配失败)[……]信息的同时,偶尔出现[完整GC(分配失败)……]信息,则也可以认为n的值是合适的。

6确保临时文件不能太小。

6调参

一般来说通过调整n,就基本可以满足sortx的性能了,如果还想进一步追求性能,就需要调参了。默认分配的年轻代只占堆的3/10,而年老代那7/10的内存在sortx这种计算时显得作用不大。如果想调整这个比例,又允许sortx使用一个专门的启动配置,则可以使用参数- xx: NewSize进行调整。

例如,- xx: NewSize=5 g,就指定年轻代的大小是5 g。

提示一下,调整的时候,年老代的空间也不能留的太少,占整个堆的1/5是合适的。这是因为Java的分配策略还有很多复杂情况,比如总空间够但不连续时,仍会直接把对象装入年老代。类似的情况还有一些,不再赘述。

同样地,伊甸园和S1, S2的比例也会影响性能,如果想调整这个比例也可以使用参数- xx: SurvivorRatio。例如- xx: SurvivorRatio=1表示伊甸园:S1, S2=1:1:1.-XX: SurvivorRatio=8表示伊甸园:S1, S2=8:1:1。

怎样通过优化JVM参数配置从而提升性能