JVM调优相关

 一、回收器的选择(默认使用串行收集器)

  1、串行垃圾收集器:单线程,无需线程交互,效率高;适用于单核处理器,或者小数据量(100M)情况下 ; -XX:UseSerialGC : 打开串行收集器

  2、并行垃圾收集器:多线程,减少垃圾回收时间,适用于多核处理器;

    -XX:UseParallelGC : 打开串行收集器,仅用于新生代;

    -XX:UseParallelOldGC: 打开串行收集器,仅用于老年代;

    -XX:UseParallelGCThreads=n;垃圾回收线程数量,n 建议设置成CPU的核数

    -XX:MaxGcPauseMills=n;垃圾回收的时候,回收空间,用户线程创建空间,为避免回收时同时开辟和回收空间,所以回收时会暂停所有用户线程,n:表示最大暂停时间

    -XX:GCTimeRatio=n;这个值会影响应用程序的吞吐量,吞吐量 = 垃圾回收时间 / 非垃圾回收时间;公式为 1 / (1 + n);默认99 表示:1%的时间用于垃圾回收

  3、并发垃圾收集器:可以保证大部分工作都并发进行(应用不停止),垃圾回收只暂停很少的时间,主要减少老年代的暂停时间,此收集器适合对响应时间要求比较高的中、大规模应用

    -XX:UseConcMarkSweepGC:打开并发垃圾收集器线程

    使用并发垃圾收集器线程常见错误:Concurrent Mode Failure,在回收垃圾的同时产生的垃圾,所以并发收集器一般需要20%的预留空间用于这些浮动垃圾

    -XX:CMSInitiatingOccupancyFraction=<N>  指定还有多少剩余堆时开始执行并发收集

  4、总结

     串行处理器:

    --适用情况:数据量比较小(100M左右);单处理器下并且对响应时间无要求的应用。 
    --缺点:只能用于小型应用

   并行处理器:

    --适用情况:“对吞吐量有高要求”,多CPU、对应用响应时间无要求的中、大型应用。举例:后台处理、科学计算。 
    --缺点:垃圾收集过程中应用响应时间可能加长

   并发处理器:

    --适用情况:“对响应时间有高要求”,多CPU、对应用响应时间有较高要求的中、大型应用。举例:Web服务器/应用服务器、电信交换、集成开发环境。

 

二、常用配置举例

 

  1、基本配置

java -Xmx3550m -Xms3550m -Xmn2g –Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxPermSize=16m -XX:MaxTenuringThreshold=0

  -Xmx3550 : 设置最大内存为3550M

  -Xms3550 :设置最小内存为3550M;和最大内存一样,为了避免每次垃圾回收完成,JVM重新分配内存带来的消耗

  -Xmn2g :年轻代内存为2G,整个堆的大小 = 年轻代 + 老年代 + 永久代,永久代一般固定为64M,所以增大年轻代,会使老年代减小;Sun官方推荐配置为整个堆的 3/8

  -Xss128k :设置每个线程的堆栈大小为128K,JDK5以后每个线程堆栈大小为1M,减小这个值,可以生成更多的线程,但是操作系统对一个进程内的线程有限制,一般在3000~5000之间

  -XX:NewRatio=4:设置年轻代(eden + 2 * survivor)和与老年代的比值,4:表示年轻代和老年代的比值是1:4,年轻代占全部的1/5

  -XX:Survivortatio=4:设置年轻代中的 eden 区和 survivor的比值,4:表示两个survivor区与一个eden区的比值,1个s区占整个年轻代的1/6

  -XX:MaxPermSize=16m:设置元空间(老年代)的大小

  -XX:MaxTenuringThreshold=0:设置垃圾的最大年龄,设置为0,表示垃圾不经过survivor区,直接进入老年代,此值越大,对象在年轻代存活的时间越长,提高效率,增加在年轻代被回收的概率

 

  2、吞吐量优先的并行收集器常有配置

    一般吞吐量优先的应用都有一个很大的年轻代和一个较小的年老代,年轻代使用并行收集器。原因是,这样可以尽可能回收掉大部分短期对象,减少中期的对象,而年老代尽存放长期存活对象。

java -Xmx3550m -Xms3550m -Xmn2g –Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxPermSize=16m -XX:MaxTenuringThreshold=0 
-XX:UseParallelGC -XX:ParallelGCThreads=20

 -XX:UseParallelGC:使用并行收集器,仅对新生代有效

 -XX:ParallelGCThreads=20:使用并行收集器时,并行垃圾收集的线程数,最好和集器的核数一样

-XX:UseParallerOldGC  -XX:MaxGCPauseMillis=100 -XX:+UseAdaptiveSizePolicy

 -XX:UseParallelOldGC:配置老年代使用并行收集器

 -XX:MaxGCPauseMillis=100:设置每次年轻代垃圾回收的最长时间,如果无法满足改时间,JVM会自动调整

    -XX:UseAdaptiveSizePolicy:设置此值后,并发收集器会自动选择年轻代大小和相应survivor区的比例来达到系统规定的最低时间和频率,建议使用并行收集器时,一直打开

 

   3、响应时间优先的并发收集器

    年老代使用并发收集器,所以其大小需要小心设置,一般要考虑并发会话率会话持续时间等一些参数。如果堆设置小了,可以会造成内存碎片、高回收频率以及应用暂停而使用传统的标记清除方式;

    如果堆大了,则需要较长的收集时间。最优化的方案,一般需要参考以下数据获得:

      a. 并发垃圾收集信息

      b. 持久代并发收集次数

      c. 传统GC信息

      d. 花在年轻代和年老代回收上的时间比例减少年轻代和年老代花费的时间,一般会提高应用的效率

 

java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC

  -XX:UseConcMarkSweepGC:设置老年代为并发手机

  -XX:NewRatio=4:新生代和老生的的比值,此值会失效,建议使用-Xmn来设置

  -XX:+UseParNewGC:设置年轻代为并发收集

java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseConcMarkSweepGC -XX:CMSFullGCsBeforeCompaction=5 -XX:+UseCMSCompactAtFullCollection
-XX:CMSFullGCsBeforeCompaction

  -XX:CMSFullGCsBeforeCompaction:由于并发收集器不对内存空间进行压缩、整理,所以运行一段时间后会产生碎片,使得允许时效率降低,此值设置运行多少次以后对内存进行压缩和整理

  4、辅助信息

    JVM提供了大量的命令行参数,用于调试

    -XX:+PrintGC:输出形式:[GC 118250K->113543K(130112K), 0.0094143 secs] [Full GC 121376K->10414K(130112K), 0.0650971 secs]

    -XX:+PrinfGCDetails:输出形式 [GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs] [GC [DefNew: 8614K->8614K(9088K), 0.0000665 secs][Tenured:                   112761K->10414K(121024K), 0.0433488 secs] 121376K->10414K(130112K), 0.0436268 secs]

    -XX:+PrintGCTimeStamps  -XX:+PrintGC :显示GC时间

    -XX:+PrintGCApplicationConcurrentTime:打印每次垃圾回收钱,程序未中断的可执行时间

    -XX:+PrintGCApplicationStoppedTime:垃圾回收期间程序暂停的时间

    -XX:PrintHeapAtGC:打印GC前后的堆栈信息

    -Xloggc:filename:和上面的配合使用。把相关日志记录到文件

 

三、常见异常错误:

  1、java.lang.OutOfMemoryError: Java heap space

    原因:这是最典型的内存泄漏方式,简单说就是所有堆空间都被无法回收的垃圾对象占满,虚拟机无法再在分配新空间

    解决:一般就是根据垃圾回收前后情况对比,同时根据对象引用情况(常见的集合对象引用)分析,基本都可以找到泄漏点

  2、java.lang.OutOfMemoryError: PermGen space

    原因:元空间不足,无法为新的class分配存储空间而引发的异常,主要时反射生成大量的类不断被加载导致

    解决:设置-XX:MaxPermSize=64m

  3、java.lang.StackOverflowError

    原因:栈溢出,一般是递归调用没有返回

    解决:解决代码递归和循环调用

  4、Fatal: Stack size too small

    原因:设置的栈太小

    解决:-Xss=2m,设置栈的太小,一般默认为1m;无法解决根本问题,主要找到代码泄露的问题

  5、java.lang.OutOfMemoryError: unable to create new native thread

    原因:因操作系统资源限制不能创建线程

    解决:-Xss=128k,无法减小线程数量的情况下,将栈设置的足够小,就可以创建更多的线程;无法解决根本问题,重新设计减少线程数量

  

posted @ 2019-10-16 11:52  wangshunyao  阅读(265)  评论(0)    收藏  举报