jvm参数设置需要注意的地方

  我们要尽量减少 Full gc 的次数(tenured generation 一般比较大,收集的时间较长,频繁的Full gc会导致应用的性能收到严重的影响)。

堆内存GC      

​ JVM(采用分代回收的策略),用较高的频率对年轻的对象(young generation)进行YGC,而对老对象(tenured generation)较少(tenured generation 满了后才进行)进行Full GC。这样就不需要每次GC都将内存中所有对象都检查一遍。

非堆内存不GC

​ GC不会在主程序运行期对PermGen Space进行清理,所以如果你的应用中有很多CLASS(特别是动态生成类,当然permgen space存放的内容不仅限于类)的话,就很可能出现PermGen Space错误。

1.-Xmn 与-XX:NewRatio 不要同时设置

2.-Xss一定要设置,JDK5.0以后每个线程堆栈大小为1M,对一般的应用来说,256K足够了,如果发生StackOverFlow错误,那么加大这个值也没用。

jvm 栈 和本地方法栈可能存在的异常:

StackOverFlowError:线程请求的栈深度>虚拟机所允许的深度
OutOfMemory:当扩展时无法申请到足够的内存(大部分虚拟机都允许动态扩展,java虚拟机规范也允许固定长度)

3.设置-XX:+DisableExplicitGC**,避免RMI或应用显示调用System.gc().如果有此类调用gc日志中会含有System标志。

修正:

1.jdk6 u32之前存在一个bug,某些情况下,cms GC 不回收Dirent byte buffer,堆外内存。

2.使用这个参数可能会导致cms GC触发之前,堆外内存过大时,物理内存或地址空间不足,出现OOM错误。

因此建议:

1.不使用这个参数,改为:-XX:+ExplicitGCInvokesConcurrent

2.配置堆外内存最大空间:-XX:MaxDirectMemorySize。不配置时,默认与-Xmx值相同。可能造成OOM.

4.-XX:MaxTenuringThreshold** 对象最多!经过多少次minor GC后进入年老代。设置为0,则不经过survior拷贝,直接进入年老代。增大此值会增加对象在Minor GC被回收的几率,减小此值会增加对象进入年老代的几率。注意最多,有可能不经过那么多次,比如

4.1.大的数组对象,如果在survivor空间中相同年龄所有对象大小的累计值大于survivor空间的一半,大于或等于个年龄的对象就可以直接进入老年代,无需达到MaxTenuringThreshold中要求的年龄

4.2.配置了-XX:PretenureSizeThreshold 参数,则大于指定byte的对象直接进入年老代分配。

5.持久代GC时回收无引用的*废弃常量与无用类*。无用类需满足以下三个条件:

5.1.该类所有的实例都已经被GC,也就是JVM中不存在该Class的任何实例。

5.2.加载该类的ClassLoader已经被GC。

5.3.该类对应的java.lang.Class 对象没有在任何地方被引用,如不能在任何地方通过反射访问该类的方法。

是否对类进行回收可使用-XX:+ClassUnloading参数进行控制,还可以使用-verbose:class或者-XX:+TraceClassLoading、-XX:+TraceClassUnLoading查看类加载、卸载信息。

在大量使用反射、动态代理、CGLib等bytecode框架、动态生成JSP以及OSGi这类频繁自定义ClassLoader的场景都需要JVM具备类卸载的支持以保证永久代不会溢出

**6 -**XX:CMSInitiatingOccupancyFraction=70以上 堆内存达到多少比例时,触发CMS。需要与-XX:+UseCMSInitiatingOccupancyOnly 同时使用以保证CMS不自动触发,否则不到比例也可能触发CMS.

计算公式一:CMSInitiatingOccupancyFraction <=((Xmx-Xmn)-(Xmn-Xmn/(SurvivorRatior+2)))/(Xmx-Xmn)*100

考虑了2个救助区中一个servior不会使用的情况。

计算公式二:(Xmx-Xmn)*(100-CMSInitiatingOccupancyFraction)/100>=Xmn

统一考虑年轻代。

满足以上2个计算公式,则不会出现 concurrent model fail。及不会出现并行回收失败,降级为虚拟机串行回收(SerialGC)的情况。

7.CMS碎片问题

因为年老代的并发收集器使用标记,清除算法,所以不会对堆进行压缩.当收集器回收时,他会把相邻的空间进行合并,这样可以分配给较大的对象.但是,当堆空间较小时,运行一段时间以后,就会出现”碎片”,如果并发收集器找不到足够的空间,那么并发收集器将会停止,然后使用传统的标记,清除方式进行回收.如果出现”碎片”,可能需要进行如下配置:

-XX:+UseCMSCompactAtFullCollection:使用并发收集器时,开启对年老代的压缩.

-XX:CMSFullGCsBeforeCompaction=0:上面配置开启的情况下,这里设置多少次Full GC后,对年老代进行压缩

**8.**XMX和XMS设置一样大,MaxPermSize和MinPermSize设置一样大,这样可以减轻伸缩堆大小带来的压力。

9:promotion failed:

救助空间不足,要放到老生代,但老生代空闲空间存在碎片,导致没有足够大的连续空间来存放新生代对象的升级时,机会触发promotion failed

解决方法:

9.1.增大救助空间、增大年老代

增大救助空间就是调小-XX:SurvivorRatio这个参数是Eden区和Survivor区的大小比值,默认是32

增大年老代,调大-Xmn参数,增加新生代,或调大-XX:NewRatio,减少新生代比例,增大年老代。

9.2..去掉救助空间(不赞成)

调大-XX:SurvivorRatio到非常大的数值65536

10:Concurrent Mode Failure

并发收集器在应用运行时进行收集,所以需要保证堆在垃圾回收的这段时间有足够的空间供程序使用,否则,垃圾回收还未完成,堆空间先满了。这种情况下将会发生“并发模式失败”,此时整个应用将会暂停,进行垃圾回收

解决方法:

10.1.满足第6点的公式,可以避免这个问题。

10.2.调小CMSMaxAbortablePrecleanTime的值 尽快回收

11.**CMS默认启动的回收线程数目是(ParallelGCThreads + 3)/4)

也可以通过:-XX:ParallelCMSThreads=20 设置

12.为了减少CMS GC第二次暂停的时间,开启并行remark:-XX:+CMSParallelRemarkEnabled。如果remark还是过长的话,可以开启-XX:+CMSScavengeBeforeRemark选项,强制remark之前开始一次minor gc,减少remark的暂停时间,但是在remark之后也将立即开始又一次minor gc。

13.+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled CMS回收持久代

14.FullGC的触发条件

14.1.old空间不足 达到比例(CMSInitiatingOccupancyFraction) 或 promotion failed 或 current mode failed(这个会很悲剧)

14.2.Perm空间不足 92%

14.3.显示调用System.GC, RMI等的定时触发

14.4.YGC时的悲观策略

14.5.dump live的内存信息时(jmap –dump:live)

15.YGC时的悲观策略

15.1、在YGC执行前,min(目前新生代已使用的大小,之前平均晋升到old的大小中的较小值) > 旧生代剩余空间大小 ? 不执行YGC,直接执行Full GC: 执行YGC;

15.2、在YGC执行后,平均晋升到old的大小 > 旧生代剩余空间大小 ? 触发Full GC : 什么都不做

CMSGc时,旧生代剩余空间需要考虑CMSInitiatingOccupancyFraction

在Minor GC触发时,会检测之前每次晋升到老年代的平均大小是否大于老年代的剩余空间,如果大于,改为直接进行一次Full GC,如果小于则查看HandlePromotionFailure设置看看是否允许担保失败,如果允许,那仍然进行Minor GC,如果不允许,则也要改为进行一次Full GC

16.导致OOM的原因

1.GC overhead limit exceeded
2.Java Heap Space
3.Unable to create new native thread
4.PermGen Space
5.Direct buffer memory
6.request {} bytes for {}. Out of swap space?

猜你喜欢

转载自blog.csdn.net/wf_feng/article/details/82345741
今日推荐