zoukankan      html  css  js  c++  java
  • tomcat jvm参数优化

    根据gc(垃圾回收器)的选择,进行参数优化

    JVM给了三种选择:串行收集器、并行收集器、并发收集器,但是串行收集器只适用于小数据量的情况,所以这里的选择主要针对并行收集器和并发收集器。
    -XX:+UseSerialGC:设置串行收集器
    -XX:+UseParallelGC:设置并行收集器
    -XX:+UseParalledlOldGC:设置并行年老代收集器
    -XX:+UseConcMarkSweepGC:设置并发收集器
    

     

    串行收集器
    -XX:+UseSerialGC:设置串行收集器。
    吞吐量优先的并行收集器
    并行收集器主要以到达一定的吞吐量为目标,适用于科学技术和后台处理等。
    -XX:+UseParallelGC:设置为并行收集器。此配置仅对年轻代有效。即年轻代使用并行收集,而年老代仍使用串行收集。
    -XX:ParallelGCThreads=20:配置并行收集器的线程数,即:同时有多少个线程一起进行垃圾回收。此值建议配置与CPU数目相等。
    -XX:+UseParallelOldGC:配置年老代垃圾收集方式为并行收集。JDK6.0开始支持对年老代并行收集。
    -XX:MaxGCPauseMillis=100:设置每次年轻代垃圾回收的最长时间(单位毫秒)。如果无法满足此时间,JVM会自动调整年轻代大小,以满足此时间。
    -XX:+UseAdaptiveSizePolicy:设置此选项后,并行收集器会自动调整年轻代Eden区大小和Survivor区大小的比例,以达成目标系统规定的最低响应时间或者收集频率等指标。此参数建议在使用并行收集器时,一直打开。
    
    响应时间优先的并发收集器
    并发收集器主要是保证系统的响应时间,减少垃圾收集时的停顿时间。适用于应用服务器、电信领域等。
    -XX:+UseConcMarkSweepGC:即CMS收集,设置年老代为并发收集。它的主要适合场景是对响应时间的重要性需求大于对吞吐量的需求,能够承受垃圾回收线程和应用线程共享CPU资源,并且应用中存在比较多的长生命周期对象。CMS收集的目标是尽量减少应用的暂停时间,减少Full GC发生的几率,利用和应用程序线程并发的垃圾回收线程来标记清除年老代内存。
    -XX:CMSFullGCsBeforeCompaction=0:由于并发收集器不对内存空间进行压缩和整理,所以运行一段时间并行收集以后会产生内存碎片,内存使用效率降低。此参数设置运行0次Full GC后对内存空间进行压缩和整理,即每次Full GC后立刻开始压缩和整理内存。
    -XX:+UseCMSCompactAtFullCollection:打开内存空间的压缩和整理,在Full GC后执行。可能会影响性能,但可以消除内存碎片。
    -XX:+CMSIncrementalMode:设置为增量收集模式。一般适用于单CPU情况。
    -XX:CMSInitiatingOccupancyFraction=70:表示年老代内存空间使用到70%时就开始执行CMS收集,以确保年老代有足够的空间接纳来自年轻代的对象,避免Full GC的发生。
    

     

      其它垃圾回收参数

    -XX:+ScavengeBeforeFullGC:年轻代GC优于Full GC执行。
    -XX:-DisableExplicitGC:不响应 System.gc() 代码。
    -XX:+UseThreadPriorities:启用本地线程优先级API。即使 java.lang.Thread.setPriority() 生效,不启用则无效。
    -XX:SoftRefLRUPolicyMSPerMB=0:软引用对象在最后一次被访问后能存活0毫秒(JVM默认为1000毫秒)。
    -XX:TargetSurvivorRatio=90:允许90%的Survivor区被占用(JVM默认为50%)。提高对于Survivor区的使用率。
    

      

      推荐的JVM优化参数

    CATALINA_OPTS="
    -Xms2g   #初始堆大小
    -Xmx2g   #最大堆大小
    -Xss512k #线程栈大小,出现java.lang.StackOverflowError时增大此值
    -Xmn1000m #年轻代大小,对半分
    -XX:MetaspaceSize=128m  #元数据类存储空间大小,存储与系统内存
    -XX:MaxMetaspaceSize=512m  #最大元数据类存储空间大小
    -Xloggc:/usr/local/tomcat/logs/gc.log #记录gc日志路径
    -XX:+PrintGCDetails   #打印gc日志
    -XX:+PrintGCDateStamps  #打印gc发生的具体时间
    -XX:+PrintPromotionFailure  #打开了就知道是多大的新生代晋升到老生代引发的full gc
    -XX:-UseBiasedLocking   #取消偏向锁
    -XX:AutoBoxCacheMax=20000  #增大Integr cache
    -XX:+AlwaysPreTouch  #启动时访问并置零内存页面
    -Djava.security.egd=file:/dev/./urandom #此江湖偏方原因为Tomcat的SecureRandom显式使用SHA1PRNG算法时,初始因子默认从/dev/random读取会存在堵塞。额外效果是SecureRandom的默认算法也变成合适的SHA1了
    -XX:+ExplicitGCInvokesConcurrent  #​full gc时,使用CMS算法,不是全程停顿,必选
    -XX:+ParallelRefProcEnabled  #并行的处理Reference对象,如WeakReference,默认为false,除非在GC log里出现Reference处理时间较长的日志,否则效果不会很明显,但我们总是要JVM尽量的并行,所以设了也就设了
    -XX:+UseConcMarkSweepGC  #老年代并发收集,CMS gc
    -XX:CMSInitiatingOccupancyFraction=75  #老年代内存空间使用到75%时执行CMS收集,以确保年老代有足够的空间接纳来自年轻代的对象,避免Full GC的发生。
    -XX:+UseCMSInitiatingOccupancyOnly  #在年老代使用了初始化的比例后并发收集器启动收集
    -XX:-CMSClassUnloadingEnabled  #在CMS中清理永久代中的过期的Class而不等到Full GC
    -XX:+CMSScavengeBeforeRemark
    -XX:+HeapDumpOnOutOfMemoryError   #发生OOM时创建堆内存转储文件
    -XX:HeapDumpPath=/usr/local/tomcat/logs  #发生OOM时创建堆内存转储文件路径,在容器环境中,输出4G的HeapDump在普通硬盘会造成20秒以上的硬盘IO跑满,容易影响同一宿主机上所有其它容器
    -XX:OnOutOfMemoryError=/usr/local/tomcat/bin/stop.sh  #发生OOM记录内存转储文件后。执行的操作,可以重启或者停止服务
    -XX:ErrorFile=/usr/local/tomcat/logs/hs_err_%p.log  #jvm crash时hotspot会生成一个error文件,提供jvm状态信息
    -XX:+PrintCommandLineFlags  #将启动参数输出到catalina.out
    -XX:+PrintFlagsFinal  #启动后打印默认和更改过的参数值到catalina.out
    -XX:-OmitStackTraceInFastThrow  
    -Duser.timezone=Asia/Shanghai  #用户所在时区
    -Djavax.servlet.request.encoding=UTF-8
    -Djavax.servlet.response.encoding=UTF-8
    -Dfile.encoding=UTF-8
    -Duser.country=CN
    -Duser.language=zh
    -Djava.awt.headless=true
    -Dcom.sun.management.jmxremote.port=1099    #以下参数为开启jmx远程给监控系统连接
    -Dcom.sun.management.jmxremote.ssl=false 
    -Dcom.sun.management.jmxremote.authenticate=false 
    -Djava.rmi.server.hostname=127.0.0.1" 
    

      

    参数解释

    -XX:CMSInitiatingOccupancyFraction设置技巧:(Xmx-Xmn)*(100-CMSInitiatingOccupancyFraction)/100 >= Xmn
    例如在应用中 Xmx 是6000,Xmn 是 512,那么 Xmx-Xmn 是 5488M,也就是老年代有 5488M,CMSInitiatingOccupancyFraction=90 说明老年代到 90% 满的时候开始执行对老年代的并发垃圾回收(CMS),这时还 剩 10% 的空间是 5488*10% = 548M,所以即使 Xmn(也就是新生代共512M)里所有对象都搬到老年代里,548M 的空间也足够了,所以只要满足上面的公式,就不会出现垃圾回收时的 promotion failed,因此这个参数的设置必须与 Xmn 关联在一起。
    -Xmn:新生代的内存空间大小,注意:此处的大小是(eden+ 2 survivor space),整个堆大小 = 新生代大小 + 老生代大小 + 永久代大小。在保证堆大小不变的情况下,增大新生代后,将会减小老生代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的 3/8。
    PrintFlagsFinal
    -XX:MaxTenuringThreshold:设置垃圾最大年龄。如果设置为0的话,则新生代对象不经过 Survivor 区,直接进入老年代。对于老年代比较多的应用(需要大量常驻内存的应用),可以提高效率。如果将此值设置为一 个较大值,则新生代对象会在 Survivor 区进行多次复制,这样可以增加对象在新生代的存活时间,增加在新生代即被回收的概率,减少Full GC的频率,这样做可以在某种程度上提高服务稳定性。该参数只有在串行 GC 时才有效,这个值的设置是根据本地的 jprofiler 监控后得到的一个理想的值,不能一概而论原搬照抄。
    -XX:+UseCMSCompactAtFullCollection  #打开内存空间的压缩和整理,在Full GC后执行。可能会影响性能,但可以消除内存碎片,配合CMS,默认为true,不需要显式设置
    -XX:CMSFullGCsBeforeCompaction=0  #上面配置开启的情况下,这里设置多少次Full GC后,对年老代进行压缩,配合CMS,默认应该是开启

      

    查看本机默认参数命令

    java -XX:+PrintFlagsInitial

    查看配置堆情况和使用情况

    jmap -heap 2975

    配置思路需要考虑的是 Java 提供的垃圾回收机制。虚拟机的堆大小决定了虚拟机花费在收集垃圾上的时间和频度。收集垃圾能够接受的速度和应用有关,应该通过分析实际的垃圾收集的时间和频率来调整。假如堆的大小很大,那么完全垃圾收集就会很慢,但是频度会降低。假如您把堆的大小和内存的需要一致,完全收集就很快,但是会更加频繁。调整堆大小的的目的是最小化垃圾收集的时间,以在特定的时间内最大化处理客户的请求。在基准测试的时候,为确保最好的性能,要把堆的大小设大,确保垃圾收集不在整个基准测试的过程中出现。

    假如系统花费很多的时间收集垃圾,请减小堆大小。一次完全的垃圾收集应该不超过 3-5 秒。假如垃圾收集成为瓶颈,那么需要指定代的大小,检查垃圾收集的周详输出,研究垃圾收集参数对性能的影响。当增加处理器时,记得增加内存,因为分配能够并行进行,而垃圾收集不是并行的。

    调优总结

    年轻代大小选择
    1.响应时间优先的应用:尽可能设大,直到接近系统的最低响应时间限制(根据实际情况选择)。在此种情况下,年轻代收集发生的频率也是最小的。同时,减少到达年老代的对象。
    2.吞吐量优先的应用:尽可能的设置大,可能到达Gbit的程度。因为对响应时间没有要求,垃圾收集可以并行进行,一般适合8CPU以上的应用。

    年老代大小选择
    1.响应时间优先的应用:年老代使用并发收集器,所以其大小需要小心设置,一般要考虑并发会话率和会话持续时间等一些参数。如果堆设置小了,可以会造成内存碎片、高回收频率以及应用暂停而使用传统的标记清除方式;如果堆大了,则需要较长的收集时间。最优化的方案,一般需要参考以下数据获得:
      1.并发垃圾收集信息
      2.持久代并发收集次数
      3.传统GC信息
      4.花在年轻代和年老代回收上的时间比例
    减少年轻代和年老代花费的时间,一般会提高应用的效率

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

    3.较小堆引起的碎片问题
    因为年老代的并发收集器使用标记、清除算法,所以不会对堆进行压缩。当收集器回收时,他会把相邻的空间进行合并,这样可以分配给较大的对象。但是,当堆空间较小时,运行一段时间以后,就会出现“碎片”,如果并发收集器找不到足够的空间,那么并发收集器将会停止,然后使用传统的标记、清除方式进行回收。如果出现“碎片”,可能需要进行如下配置:
    -XX:+UseCMSCompactAtFullCollection:使用并发收集器时,开启对年老代的压缩。
    -XX:CMSFullGCsBeforeCompaction=0:上面配置开启的情况下,这里设置多少次Full GC后,对年老代进行压缩

      

    常见的 Java 内存溢出有以下三种

    (1) java.lang.OutOfMemoryError: Java heap space —-JVM Heap(堆)溢出

    JVM 在启动的时候会自动设置 JVM Heap 的值,其初始空间(即-Xms)是物理内存的1/64,最大空间(-Xmx)不可超过物理内存。可以利用 JVM提供的 -Xmn -Xms -Xmx 等选项可进行设置。Heap 的大小是 Young Generation 和 Tenured Generaion 之和。在 JVM 中如果 98% 的时间是用于 GC,且可用的 Heap size 不足 2% 的时候将抛出此异常信息。

    解决方法:手动设置 JVM Heap(堆)的大小。  
    (2) java.lang.OutOfMemoryError: PermGen space  —- PermGen space溢出。

    PermGen space 的全称是 Permanent Generation space,是指内存的永久保存区域。为什么会内存溢出,这是由于这块内存主要是被 JVM 存放Class 和 Meta 信息的,Class 在被 Load 的时候被放入 PermGen space 区域,它和存放 Instance 的 Heap 区域不同,sun 的 GC 不会在主程序运行期对 PermGen space 进行清理,所以如果你的 APP 会载入很多 CLASS 的话,就很可能出现 PermGen space 溢出。

    解决方法: 手动设置 MaxPermSize 大小

    (3) java.lang.StackOverflowError   —- 栈溢出

    栈溢出了,JVM 依然是采用栈式的虚拟机,这个和 C 与 Pascal 都是一样的。函数的调用过程都体现在堆栈和退栈上了。调用构造函数的 “层”太多了,以致于把栈区溢出了。通常来讲,一般栈区远远小于堆区的,因为函数调用过程往往不会多于上千层,而即便每个函数调用需要 1K 的空间(这个大约相当于在一个 C 函数内声明了 256 个 int 类型的变量),那么栈区也不过是需要 1MB 的空间。通常栈的大小是 1-2MB 的。
    通常递归也不要递归的层次过多,很容易溢出。

    解决方法:修改程序。

    参考博客:

    https://blog.csdn.net/kthq/article/details/8618052

    http://blog.chopmoon.com/favorites/231.html

    http://www.importnew.com/13954.html

    https://blog.csdn.net/yjl33/article/details/78890363 

    报错解决:

    1、java.lang.StackOverflowError异常

    原因:Java中,栈的大小通过-Xss来设置,当栈中存储数据比较多时,需要适当调大这个值

    堆和栈的概念:http://pengjiaheng.iteye.com/blog/518623   https://www.cnblogs.com/sxdcgaq8080/p/7150568.html

  • 相关阅读:
    Linux 系统下 “账户管理”
    gulp添加版本号解决缓存问题
    vue3.0的proxy浅析内层绑定原理
    rem用font-size布局与easyui的datagrid通用,出现table不显示
    堆与栈 | 对象深浅拷贝
    vue双向绑定原理值Object.defineProperty
    bootstrap模态框不出,只出现黑色蒙层bug
    Appdelegate 导航操作
    CLLocationManager 位置定位
    导航创建
  • 原文地址:https://www.cnblogs.com/shansongxian/p/9798998.html
Copyright © 2011-2022 走看看