Jvm组成以及调优

  Jvm的内存由三部分组成Eden,S0,S1,Old以及Metaspace(JDK1.8之前的Perm区)五部分组成;

(图片摘自VisualVM的Visual GC插件)

  抽象为三代:新生代(Eden,S0,S1);老年代(old)以及持久代(Metaspace/Perm);

  java -server -Xms100m -Xmx2g -XX:NewSize=100m -XX:SurvivorRatio=8 cs.jar

  -server表示Jvm运行模式是服务器,服务器的特点就是启动慢,但是运行过程中内存比较平稳;客户端想反,启动比较快,但是长期运行来看性能等步入服务器好。

  设定大小,Xms100m是堆的初始大小为100m,新生代以及老年点的初始化总大小,对于持久代而言,不属于堆空间,属于栈空间(从大面来讲,JVM内存区分为两部分,堆空间和栈空间(perm/metaspace);堆空间,又可以细分为Eden,Survivor0,Survivor1三部分);常量,方法区空间分配等都是会使用持久代空间,所以这部分空间也是比较稳定(除非使用动态技术加载新类,导致增加空间分配方法区等);Xmx2g,堆最大空间为2G;

  推荐堆空间为内存空间的1/4,-Xmn150m指定Eden大小;-XX:NewSize=100m是指分配的新生代的初始化大小(包括Eden,S0以及S1总大小)。如下图所示:Eden Space以及S0,S1大小都有两个值,比如Eden Space里面是483.000M,88.000M,就是指Eden最大空间为483(有-Xmn指定),88M则是指初始化分配大小为88M,而且只要达到了这个88M就会尝试进行回收。因为达到了88之后并不能马上进行回收,只是设定了“安全点”,要等到所有的线程都跑到了“安全点”才能够进行回收,所以,在这个过程中还是需要继续分配内存,所以在指定Xmn以及NewSize的时候,要保证Xmn的大小要大于NewSize分配的值。

  注:在jvm args中有的-X,有的是-XX:,两者区别在于-X是稳定的,各个版本的jvm都支持,包括前后兼容;但是-XX则是不稳定,并不保证各个版本间延续,兼容。

  讲了EdenSpace空间的分配,那么Survivor的分配呢?首先要了解Eden以及Survivor之间的组合实现的“复制”机制,然后是商用Jvm设计的两者关系是按照比例的,Sun推荐两者比例是8,即Eden占80%,两个Survivor各占10%,IBM曾经有一个调查支持这个比例,就是98%的对象是“朝生夕死”的,所以复制到的空间设计的可以小一些。下图是没有设置XX:SurvivorRatio,看得出来默认值是3:1:1,Eden60%,Survivor各占20%,如果指定值为8之后,Survivor大小变成了48M,但是最小的空间大小并没有发生变化;可见-XX:NewSize分配大小就是默认的8:1:1,并不受SurvivorRator影响太大(即使相同的surviorRatio,每次启动JVM分配空间也有些许偏差)。

 

  1.通过VisualGC需要跟踪的对于新生代的回收是否过于频繁,如果频繁说明你设置的NewSize大小有问题,尝试调整高一些。调整新生代,老年代的大小是一个平衡,就是空间大,GC次数少,但是一次GC时间可能长(因为空间大了);所以在大小方面需要进行调试,一次GC控制在几毫秒,不是很频繁是可以接受的。

  2.要关注老年代的回收,因为老年代回收将会触发Full GC,即全堆的回收,所以停顿时间(Stop-Of-The-World)会比较长,对于老年代要留有足够的空间,避免Full GC间隔较短就触发。

  3.对于高吞吐量的场景下,在VisualVM的Monitor监控下发现内存使用长期持续在300M(-XX:NewSize=300M),形成一片,这是正常的,首先jvm声明了新生代总大小为300M,那么内存就会在高吞吐场景下上扬到300之后,迅速下降(垃圾回收),所以在VVM中时间点之间的距离将会越来越小(vvm将会尝试在一个折线图展示从开始监控到当前时间点的数据),形成一片,说明有增加有释放,因为是高吞吐量,所以内存会不断上升;因为有Minor GC所以会不断回收,所以这个持续过程是正常的

 

posted on 2017-03-11 20:28  下士闻道  阅读(1230)  评论(0编辑  收藏  举报

导航