当前位置: 首页 > news >正文

建设部电教中心网站网站优化心得

建设部电教中心网站,网站优化心得,无人区在线影院免费高清,网站优化任务文章目录 前言性能调优#xff08;上#xff09;线上问题排查工具汇总JVM调优#xff08;中#xff09;Java中不得不了解的OOM Error 一.JVM参数1.参数分类2.非稳定参数#xff08;-XX#xff09;说明3.查询JVM默认参数及运行时生效参数4.常用参数5.GC日志相关参数6.发生… 文章目录 前言性能调优上线上问题排查工具汇总JVM调优中Java中不得不了解的OOM Error 一.JVM参数1.参数分类2.非稳定参数-XX说明3.查询JVM默认参数及运行时生效参数4.常用参数5.GC日志相关参数6.发生OOM时Dump堆内存快照相关参数7.收集器参数 二.GC日志启用与分析1.输出GC日志2.分析GC日志 三.调优总结1.JVM 调优需要做些什么2.调优原则3.JVM调优的时机4.JVM调优的目标5.JVM调优的步骤6.常用调优策略1.选择合适的垃圾回收器2.调整堆内存大小3.设置符合预期的停顿时间4.调整内存区域大小比率5.调整对象晋升老年代的年龄阀值6.调整大对象的大小阀值7.调整GC的触发时机8.调整 JVM本地内存大小 7.常见问题问题 1CPU使用率高问题 2CPU Load 高问题 3持续 FullGC问题 4线程池满问题 5NoSuchMethodException问题 6JVM生成hs_err_pid开头的文件常见问题汇总 四.调优实例1-初窥门径1.浏览量暴增后网站响应速度变慢2.后台导出数据引发的OOM3.单个缓存数据过大导致的系统CPU飚高4.CPU经常100% 问题定位5.内存飚高问题定位6.数据分析平台系统频繁 Full GC7.线程锁死/无限等待 五.调优实例2-登堂入室1.CPU 利用率高/飙升第一步定位出问题的线程方法 1: 传统的方法方法 2: show-busy-java-threads方法 3: arthas threadarthas使用 第二步:具体问题具体分析场景1CPU占比最高的都是GC线程场景2CPU占比最高的都是业务线程 2.频繁 GCGC处理过程GC 原因及定位(常见问题 3持续 FullGC) 前言 性能调优上线上问题排查工具汇总 【Jvm】性能调优上线上问题排查工具汇总 JVM调优中Java中不得不了解的OOM Error 【Jvm】性能调优中Java中不得不了解的OOM Error 一.JVM参数 1.参数分类 标准参数-所有的JVM实现都必须实现该功能且向后兼容 查看标准参数方法: java -help非标准参数-X默认Jvm实现该功能但是不保证所有jvm实现都满足且不保证向后兼容 查看非标准参数方法: java -X非稳定参数-XX各个jvm实现会有所不同将来可能会随时弃用需慎重使用 2.非稳定参数-XX说明 查看非稳定参数方法 java -XX:PrintFlagsInitial语法 Boolean类型格式:-XX:[±]option表示启用或者禁用name属性-XX:option 启用选项如-XX:PrintGCDetails-XX:-option 不启用选项如-XX:-PrintGCDetails非Boolean类型格式:-XX:namevalue设置name属性的值是value-XX:namenumber 设置name属性的值是value数字类型值可跟单位如-XX:NewSize2m-XX:namestring 设置name属性的值是value字符串值如-XX:HeapDumpPath./dump.core 非稳定参数主要分3类 行为参数Behavioral Options用于改变jvm的一些基础行为如-XX:-UseSerialGC 启用串行GC-XX:-UseParallelGC 启用并行GC-XX:-UseConcMarkSweepGC 启用CMS,对老年代采用并发标记交换算法进行GC性能调优Performance Tuning用于jvm的性能调优如-XX:MaxNewSizesize 年轻内存的最大值-XX:NewRatio2 年轻代内存容量与老年代内存容量的比例-XX:ThreadStackSize512 设置线程栈大小若为0则使用系统默认值调试参数Debugging Options一般用于打开跟踪、打印、输出等jvm参数用于显示jvm更加详细的信息如-XX:-PrintGCDetails 每次GC时打印详细信息-XX:-PrintGCTimeStamps 打印每次GC的时间戳-XX:-HeapDumpOnOutOfMemoryError 当首次遭遇OOM时导出此时堆中相关信息-XX:HeapDumpPath./java_pidpid.hprof 指定导出堆信息时的路径或文件名3.查询JVM默认参数及运行时生效参数 java -XX:PrintFlagsInitial : 输出JVM参数的默认值java -XX:PrintFlagsFinal -version: 输出运行程序时生效的值java -XX:PrintCommandLineFlags -version : 查询当前使用的 JVM命令即被用户修改过的参数值 第1列参数数据类型 第2列参数名称 第3列””表示第四列是参数的默认值如果是: 表明了参数被用户或者JVM赋值了(重点关注) 第4列参数值 第5列参数的类别4.常用参数 #初始堆大小等于-XX:InitialHeapSize默认为物理内存的1/64(1GB)。如堆空间初始化大小为6m,可写为-Xms6291456 或 -Xms6144k 或 -Xms6m #默认空余堆内存小于40%时JVM就会增大堆直到-Xmx的最大限制#空闲最小堆占比通过-XX:MinHeapFreeRatio调整,默认为40计算公式为堆空闲占比(当前空闲堆大小/当前堆总大小)*100在每次GC之后如果堆空闲占比 空闲最小堆占比则需要进行堆扩容#最好将-Xms和-Xmx设为相同值避免每次GC完成后JVM重新分配内存 -Xms #最大堆大小。等于-XX:MaxHeapSize默认为物理内存的1/4设如设置堆空间的最大值为80m,可写为-Xmx83886080 或 -Xmx81920k 或 -Xmx80m #默认空余堆内存大于70%时JVM会减少堆直到-Xms的最小限制,建议不要超过系统总可用内存的1/2#空闲最大占比通过-XX:MaxHeapFreeRatio调整,默认为70计算公式为堆空闲占比(当前空闲堆大小/当前堆总大小)*100在每次GC之后如果堆空闲占比 空闲最大堆占比则需要进行堆缩容 -Xmx#年轻代初始化大小等同-Xns -XX:NewSize #年轻代的最大值等同-Xmneden 2 survivor space)。如设置256m大小的年轻代-Xmn256m 或 -Xmn262144k 或-Xmn268435456 #. 增大年轻代后,将会减小年老代大小.此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8 -XX:MaxNewSize #设置年轻代(包括Eden和两个Survivor区)和老年代的比例。默认值是2。表示年轻代与年老代比值为1:2年轻代占整个年轻代年老代和的1/3 #XmsXmx并且设置了Xmn的情况下该参数不需要进行设置。 -XX:NewRatio #设置Eden区与与两个Survivor区的内存占比默认为8即8:1:1即Eden8Survivor From1Survivor To1。一个Survivor区占整个年轻代的2/10 -XX:SurvivorRatioratio#对象晋升到老年代的年龄阈值,默认为15如果设为0,则年轻代对象不经过Survivor区,直接进入老年代. 对于老年代比较多的应用,可以提高效率 #如果设为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象在年轻代的存活时间,增加在年轻代即被回收的概率 #该参数只有在串行GC时才有效. -XX:MaxTenuringThresholdthreshold#大对象直接晋升老年代的阈值默认0单位只能使用byte如3m只能写为3145728 #年轻代采用Parallel Scavenge GC时无效 另一种直接在老年代分配的情况是大数组对象,且数组中无外部引用对象. -XX:PretenureSizeThresholdsize#大对象直接晋升老年代的阈值默认0单位只能使用byte如3m只能写为3145728 -XX:PretenureSizeThresholdsize#设置线程的栈大小可跟单位如-Xss2m # JDK5.0后默认1M(之前默认为256K).根据的线程所需内存大小进行调整 #在相同物理内存下,减小这个值能生成更多的线程.但是操作系统对一个进程内的线程数还是有限制的,不能无限生成, 经验值在3000~5000左右 #一般小的应用 如果栈不是很深 应该是128k够用的大的应用建议使用256k。这个选项对性能影响比较大需要严格的测试。 -Xss#设置永久代(perm gen)的初始大小默认为内存的1/64JDK1.7方法区 -XX:PermSizesize #设置永久代的最大值默认为内存的1/4JDK1.7方法区 -XX:MaxPermSizesize #设置元空间的大小JDK1.8元空间 -XX:MetaspaceSizesize #设置元空间的最大值JDK1.8元空间 -XX:MaxMetaspaceSizesize#限制GC的运行时间。如果GC耗时过长就抛OOM默认true,表启用 #GC Overhead limit exceeded原因通过统计GC时间来预测是否要OOM了当超过98%的时间用来做GC并且回收了不到2%的堆内存就会抛出该错误提前预知没啥用该OOM还是会OOM建议关闭 -XX:UseGCOverheadLimit #Full GC时是否先YGC默认false表关闭 -XX:CollectGen0First 5.GC日志相关参数 #打印GC基本信息 -XX:PrintGC: #输出形式: [GC 118250K-113543K(130112K), 0.0094143 secs] [Full GC 121376K-10414K(130112K), 0.0650971 secs] #打印gc详细信息 -XX:PrintGCDetails #输出形式:[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]#GC时打印进程启动到现在经历的时间 -XX:PrintGCTimeStamps #输出形式:11.851: [GC 98328K-93620K(130112K), 0.0082960 secs]#输出GC的时间戳 -XX:PrintGCDateStamps #输出形式:2013-05-04T21:53:59.2340800: [GC 98328K-93620K(130112K), 0.0082960 secs]#GC时打印应用被暂停时间 -XX:PrintGCApplicationStoppedTime #输出形式:Total time for which application threads were stopped: 0.0468229 seconds#GC时打印应用执行时间 -XX:PrintGCApplicationConcurrentTime #输出形式:Application time: 0.5291524 seconds#打印每次GC前后的详细堆栈信息 -XX:PrintHeapAtGC#将GC日志输出到指定文件(默认打印到控制台)默认为应用启动路径的相对路径下可使用绝对路径 -Xloggc:../logs/gc.log #Java 9及更高版本 #日志文件的输出路径,如-Xlog:gc*:file/opt/tmp/myapp-gc.log -Xlog:gc*:filegc-log-file-path6.发生OOM时Dump堆内存快照相关参数 #如果出现了OutOfMemoryError异常就把堆内信息Dump出来 -XX:HeapDumpOnOutOfMemoryError#保存Dump文件的路径如果不指定默认为当前启动JVM的目录默认文件名java_pid_date_time_heapDump.hprof -XX:HeapDumpPath/tmp/heapdump.hprof#当出现OOM时指定某个脚本来完成一些动作比如邮件通知、自动重启等 -XX:OnOutOfMemoryErrorsh ~/restart.sh 7.收集器参数 -XX:-UseSerialGC 启用串行GC即采用SerialSerial Old组合GC。串行GC最适合小而简单的应用不需要垃圾回收的特定功能。-XX:UseParNewGC: 使用ParNewSerial Old收集器组合-XX:-UseParallelGC年轻代启用并行GC,年老代使用串行GC,即采用Parallel ScavengeSerial Old组合GC-Server模式下的默认组合 -XX:UseParallelOldGC: 老年代启用并行GC(JDK1.6)即使用Parallel Scavenge Parallel Old组合收集器-XX:UseConcMarkSweepGC: 使用ParNewCMSSerial Old组合并发收集优先使用ParNewCMS当用户线程内存不足时采用备用方案Serial Old收集。-XX:UseG1GC: 启用G1收集器。适用于多核和大内存服务器。G1收集器很大概率满足GC的停顿时间要求同时保持一个很好的吞吐量。G1垃圾收集器适合那些具有超大堆空间6GB左右或更多且对GC延迟需求很高低于0.5秒的稳定且可预测的暂停时间的应用。-XX:UseZGC: 在JDK 11当加入是一款低停顿高并发支撑TB级别内存的收集器。ZGCZ Garbage Collector 是一款性能比 G1 更加优秀的垃圾收集器。ZGC 第一次出现是在 JDK 11 中以实验性的特性引入这也是 JDK 11 中最大的亮点。在 JDK 15 中 ZGC 不再是实验功能可以正式投入生产使用了使用 –XX:UseZGC 可以启用 ZGC。收集器相关配套参数看这两篇文章即可 常见性能性能参数常用JVM虚拟机参数说明 二.GC日志启用与分析 1.输出GC日志 GC日志相关参数发生OOM时dump堆内存快照相关参数 2.分析GC日志 配置以下JVM参数发生GC时将日志输出到指定文件中 #显示GC的详细信息 应用执行的时间 打应用被暂停的时间 gc信息输出到/data/jvm_log/gc.log文件中 -XX:PrintGCDetails -XX:PrintGCDateStamps -XX:PrintGCApplicationConcurrentTime -XX:PrintGCApplicationStoppedTime -Xloggc:/data/jvm_log/gc.logYongGC/MinorGC日志 2019-04-18T14:52:06.7900800: 2.653: [GC (Allocation Failure) [PSYoungGen: 33280K-5113K(38400K)] 33280K-5848K(125952K), 0.0095764 secs] [Times: user0.00 sys0.00, real0.01 secs]含义 2019-04-18T14:52:06.7900800当前时间戳: 2.653应用启动基准时间: [GC (Allocation Failure) [PSYoungGen表示 Young GC: 33280K年轻代回收前大小-5113K年轻代回收后大小(38400K年轻代总大小)] 33280K整个堆回收前大小-5848K整个堆回收后大小(125952K堆总大小), 0.0095764耗时 secs] [Times: user0.00用户耗时 sys0.00系统耗时, real0.01实际耗时 secs]FullGC日志 2019-04-18T14:52:15.3590800: 11.222: [Full GC (Metadata GC Threshold) [PSYoungGen: 6129K-0K(143360K)] [ParOldGen: 13088K-13236K(55808K)] 19218K-13236K(199168K), [Metaspace: 20856K-20856K(1069056K)], 0.1216713 secs] [Times: user0.44 sys0.02, real0.12 secs]含义 2019-04-18T14:52:15.3590800当前时间戳: 11.222应用启动基准时间: [Full GC (Metadata GC Threshold) [PSYoungGen: 6129K年轻代回收前大小-0K年轻代回收后大小(143360K年轻代总大小)] [ParOldGen: 13088K老年代回收前大小-13236K老年代回收后大小(55808K老年代总大小)] 19218K整个堆回收前大小-13236K整个堆回收后大小(199168K堆总大小), [Metaspace: 20856K持久代回收前大小-20856K持久代回收后大小(1069056K持久代总大小)], 0.1216713耗时 secs] [Times: user0.44用户耗时 sys0.02系统耗时, real0.12实际耗时 secs]完整日志 Application time: 0.0044872 seconds [GC (System.gc()) [PSYoungGen: 10653K-5638K(76288K)] 10653K-5646K(251392K), 0.0022633 secs] [Times: user0.00 sys0.00, real0.00 secs] [Full GC (System.gc()) [PSYoungGen: 5638K-0K(76288K)] [ParOldGen: 8K-5381K(175104K)] 5646K-5381K(251392K), [Metaspace: 3510K-3510K(1056768K)], 0.0047247 secs] [Times: user0.00 sys0.00, real0.01 secs] Total time for which application threads were stopped: 0.0072102 seconds, Stopping threads took: 0.0000289 seconds HeapPSYoungGen total 76288K, used 1966K [0x000000076b000000, 0x0000000770500000, 0x00000007c0000000)eden space 65536K, 3% used [0x000000076b000000,0x000000076b1eb9e0,0x000000076f000000)from space 10752K, 0% used [0x000000076f000000,0x000000076f000000,0x000000076fa80000)to space 10752K, 0% used [0x000000076fa80000,0x000000076fa80000,0x0000000770500000)ParOldGen total 175104K, used 5381K [0x00000006c1000000, 0x00000006cbb00000, 0x000000076b000000)object space 175104K, 3% used [0x00000006c1000000,0x00000006c15415d0,0x00000006cbb00000)Metaspace used 3527K, capacity 4496K, committed 4864K, reserved 1056768Kclass space used 384K, capacity 388K, committed 512K, reserved 1048576K Application time: 0.0005665 seconds具体分析 [GC 和 [Full GC 表示垃圾收集器的停顿类型而不是用来区分新生代GC还是老年GC的。 如果是调用了System.gc()所触发的GC那么将显示[Full GC (System)如上所示。 接下来的“[DefNew” 或者 “[Tenured” 或者“[Perm” 表示GC发生的区域和使用的GC收集器相关。 如果是Serial收集器新生代名为“Default New Generation”,所以显示“[DefNew”。如果是ParNew收集器新生代名为“Parallel New Generation”,所以显示“[ParNew”。如果是Parallel Scavenge收集器新生代名则显示为“[PSYongGen”, 如上所示。老年代和永久代同理名称也是由收集器决定的。 后面方括号内部的 10653K-5638K(76288K)含义是 “GC前该内存区域已经使用的容量-GC后该内存区域已使用的容量该内存区域中容量” 方括号之外的 10653K-5646K(251392K) 表示“GC前Java堆已使用容量-GC后Java堆已使用容量Java堆中容量” 再往后0.0022633 secs表示该内存区域GC所占用的时间单位秒。 第一行为年轻代的大小大小为76288K。而年轻代又分为3个区域分别叫Eden和2个Survivor区(from和to)。Eden用来存放新的对象Survivor区用于 新对象 升级到老年代时的 拷贝。默认Eden:from:to比例 为 8:1:1( 通过参数–XX:SurvivorRatio设置 ) 即Eden 8/10、from 1/10 、to 1/10 默认年轻代(Young)与老年代(Old)比例为 1:2( 通过参数–XX:NewRatio设置 )即Young 1/3、Old2/3 ParOldGen为老年代大小为175104K,大约为PSYoungGen内存大小的2倍。 从JDK8开始永久代(PermGen)的概念被废弃掉了使用叫Metaspace的本地内存区来实现永久代功能。 三.调优总结 1.JVM 调优需要做些什么 JVM 调优具体表现为1.合理地配置JVM的运行内存空间 2.使用合适的垃圾回收器。 内存空间的分配设置JVM 内存分配不合理最直接的表现就是频繁 GC这会导致上下文切换(STW)等性能问题从而降低系统的吞吐量、增加系统的响应时间。具体的优化包括调整堆内存空间减少 Full GC、调整年轻代减少 MinorGC、设置合理的 Eden 和 Survivor 区的比例。选择合适的垃圾回收器GC主要指堆对象和方法区(元空间)只不过废弃常量和无用的类的回收。对于系统响应时间优先的程序可以选择 CMS 回收器或 G1 回收器而对吞吐量优先的程序则可以选择 Parallel Scavenge 回收器来提高系统的吞吐量。 2.调优原则 一般的Java项目需要进行JVM调优吗? 回答是否定的一般的项目加个xms和xmx参数就够了在没有全面监控收集性能数据进行分析之前调优就是在耍流氓 JVM调优听起来很高大上但是要认识到JVM调优应该是Java性能优化的最后一颗子弹。JVM调优需要我们观察当前系统的运行状况也就是系统的性能好坏才能判断是否需要调优。 如果系统的响应时间很短系统资源使用率也很低那我们做系统调优就完全是为了调优而调优。 因此JVM调优不是常规手段性能问题第一选择是优化程序代码最后的选择才是进行JVM调优。 JVM调优步骤 记录好日志对程序做好性能监控根据日志和性能监控数据优化程序代码使用工具通过不同的JVM参数进行压测并获得最佳配置。 3.JVM调优的时机 不得不考虑进行JVM调优的是那些情况呢 堆内存老年代持续上涨达到设置的最大值Full GC 次数频繁GC 停顿时间(STW)过长超过1秒系统内出现OutOfMemory 等内存异常系统中使用本地缓存且占用大量内存空间系统吞吐量与响应性能不高或下降 4.JVM调优的目标 吞吐量、延迟、内存占用三者类似CAP原则构成了一个不可能三角只能选择其中2个进行调优不可三者兼得。选择了其中2个必然会以牺牲另一个为代价。 低延迟GC低停顿和GC低频率低内存占用高吞吐量 下面展示了一些JVM调优的量化目标参考实例 堆内存使用率 70%;老年代内存使用率 70%;avg pause time 1秒;Full GC次数为0 或 avg pause interval 24小时 ; 注意不同应用的JVM调优量化目标是不一样的。 5.JVM调优的步骤 一般情况下JVM调优可通过以下步骤进行 分析系统运行情况分析GC日志及堆dump文件判断是否需要优化确定瓶颈问题点确定JVM调优量化目标确定JVM调优参数根据历史JVM参数来调整依次确定调优内存、延迟、吞吐量等指标对比观察调优前后的差异不断的分析和调整直到找到合适的JVM参数配置找到最合适的参数将这些参数应用到所有服务器并进行后续跟踪 以上操作步骤中某些步骤是需要多次不断迭代完成的。一般是从满足程序的内存使用需求开始的之后是时间延迟的要求最后才是吞吐量的要求要基于这个步骤来不断优化每一个步骤都是进行下一步的基础不可逆行。 6.常用调优策略 1.选择合适的垃圾回收器 单核CPU那么毫无疑问Serial 垃圾回收器是你唯一的选择。 启用Serial垃圾收集器年轻代-XX:UseSerialGC多核CPU关注吞吐量 那么选择PSPO组合。 启用PSPO,年轻代Parallel Scavenge回收器 老年代使用Parallel Old回收器 -XX:UseParallelOldGC多核CPU关注用户停顿时间JDK版本1.6或者1.7那么选择CMS。 启用CMS垃圾收集器老年代 -XX:UseConcMarkSweepGC多核CPU关注用户停顿时间JDK1.8及以上 JVM可用内存6G以上那么选择G1。 启用G1垃圾收集器-XX:UseG1GC2.调整堆内存大小 现象GC频率非常频繁。 原因堆内存太小导致需要频繁GC才能释放出足够的空间来创建新的对象所以增大堆内存的效果是非常显而易见的。 注意如果GC次数非常频繁但是每次能回收的对象非常少那么这个时候并非内存太小而可能是 内存泄露 导致对象无法回收从而造成频繁GC。 参数配置 //设置堆初始值 -Xms2g 或 -XX:InitialHeapSize2048m​ //设置堆区最大值 -Xmx2g 或 -XX:MaxHeapSize2048m​ //年轻代内存配置 -Xmn512m 或 -XX:MaxNewSize512m3.设置符合预期的停顿时间 现象程序间接性的卡顿 原因如果不设置具体的停顿时间垃圾回收器默认以吞吐量为主那么垃圾回收时间就会不稳定。 注意不要设置不切实际的停顿时间单次GC时间越短也意味着需要更多的GC次数才能回收完原有数量的垃圾. 参数配置 //GC停顿时间垃圾回收器会尝试用各种手段达到这个时间-XX:MaxGCPauseMillis 4.调整内存区域大小比率 现象某一个分代区域的GC频繁其他都正常。 原因如果对应分代区域空间不足导致需要频繁GC来释放空间在JVM堆内存无法增加的情况下可以调整对应区域的大小比率。 注意也许并非空间不足如果GC次数非常频繁但是每次能回收的对象非常少那么这个时候并非内存太小而可能是 内存泄露 导致对象无法回收从而造成频繁GC。 参数配置 //survivor区和Eden区大小比率 -XX:SurvivorRatio6 //Survivor区和Eden区占年轻代比率为1:6,两个S区2:6​//年轻代和老年代的占比-XX:NewRatio4 //表示年轻代:老年代 1:4 即老年代占整个堆的4/5默认值25.调整对象晋升老年代的年龄阀值 现象老年代频繁GC每次回收的对象很多。 原因如果晋升老年代年龄阀值过小年轻代对象很快就进入老年代了导致老年代对象变多而这些对象其实在随后的很短时间内就可以回收这时候可以调整对象的升代年龄阀值让对象不那么容易进入老年代解决老年代空间不足频繁GC问题。 注意增加了年龄之后这些对象在年轻代的存活时间会变长可能导致年轻代的GC频率增加 并且频繁复制这些新生对象的GC时间也可能变长。 参数配置 //进入老年代最小的GC年龄,年轻代对象转换为老年代对象最小年龄值默认值7-XX:InitialTenuringThreshol7 6.调整大对象的大小阀值 现象老年代频繁GC每次回收的对象很多, 而且单个对象的体积都比较大。 原因如果大量的大对象直接分配到老年代导致老年代容易被填满而造成频繁GC可设置对象直接进入老年代的大小阀值。 注意这些大对象进入年轻代后可能会使年轻代的GC频率和时间增加。 参数配置 //年轻代可容纳的最大对象,大于则直接会分配到老年代0代表没有限制。-XX:PretenureSizeThreshold1000000 7.调整GC的触发时机 现象CMSG1 经常 Full GC程序卡顿严重。 原因G1和CMS 部分GC阶段是并发进行的业务线程和GC线程一起工作也就说明GC的过程中业务线程会生成新的对象所以在GC的时需要预留一部分内存空间来容纳新产生的对象如果这个时候预留内存空间不足以容纳新产生的对象那么JVM就会停止并发收集并暂停所有业务线程STW来保证垃圾回收的正常运行。这种场景可以通过调整GC触发的时机比如在老年代占用60%就触发GC在GC线程与业务线程并行处理时可以预留足够的空间来。 注意提早触发GC会增加老年代GC的频率。 参数配置 //使用多少比例的老年代后开始CMS收集默认是68%如果频繁发生SerialOld卡顿应该调小 -XX:CMSInitiatingOccupancyFraction68​//G1混合垃圾回收周期中要包括的旧区域设置占用率阈值。默认占用率为 65%-XX:G1MixedGCLiveThresholdPercent65 8.调整 JVM本地内存大小 现象GC的频率、时间、回收的对象都正常堆内存空间充足但是报OOM 原因 JVM除了堆内存之外还有一块堆外内存这片内存也叫本地内存可是这块内存区域不足了并不会主动触发GC只有在堆内存区域触发的时候顺带会把本地内存回收了而一旦本地内存分配不足就会直接报OOM异常。 注意 本地内存异常的时候除了上面的现象之外异常信息可能是OutOfMemoryErrorDirect buffer memory。 解决方式除了调整本地内存大小之外也可以在出现此异常时进行捕获手动触发GCSystem.gc()。 参数配置 -XX:MaxDirectMemorySize7.常见问题 在线上应急过程中要记住只有一个总体目标「尽快恢复服务消除影响」。 不管处于应急的哪个阶段我们首先必须想到的是恢复问题恢复问题不一定能够定位问题也不一定有完美的解决方案也许是通过经验判断也许是预设开关等但都可能让我们达到快速恢复的目的然后保留部分现场再去定位问题、解决问题和复盘。 问题 1CPU使用率高 CPU使用率是衡量系统繁忙程度的重要指标一般情况下单纯的 CPU使用率高并没有问题它代表系统正在不断的处理我们的任务但是如果 CPU 过高导致任务处理不过来从而引起CPU Load高这个是非常危险需要关注的。 CPU使用率没有标准安全值取决于你是计算密集型还是 IO 密集型一般计算密集型应用 CPU 使用率偏高CPU Load偏低IO 密集型相反。 问题原因及定位 1.频繁 FullGC/YongGC 开启GC日志用于查看gc日志 : -XX:PrintGCDetails -Xloggc:../logs/gc.log 查看内存使用和 gc 情况jstat -gcutil pid 2.代码消耗如死循环md5 等内存态操作 使用arthas thread -n 5 查看 CPU 使用率最高的前 5 个线程堆栈 jstack 查找 查询Java 进程 idps -ef | grep java根据进程id找到 CPU占比最高的线程top -Hp pid将线程 id 转化 16 进制printf 0x%x tid 查询Java线程堆栈信息并16进制线程Id进行grep jstack pid | grep tid 问题 2CPU Load 高 load 指单位时间内活跃进程数包含运行态runnable 和 running和不可中断态 IO、内核态锁。关键字是运行态和不可中断态运行态可以联想到 Java 线程的 6 种状态如下线程 new 之后处于 NEW 状态执行 start 进入 runnable 等待 CPU 调度因此如果 CPU 很忙会导致 runnable 进程数增加不可中断态主要包含网络 IO、磁盘 IO 以及内核态的锁如 synchronized 等。 问题原因及定位 1 CPU 利用率高可运行态进程数多 排查方法见常见问题一 2.iowait等待 IO vmstat 查看 blocked 进程状况jstack -l pid | grep BLOCKED 查看阻塞态线程堆栈 3.等待内核态锁如 synchronized jstack -l pid | grep BLOCKED 查看阻塞态线程堆栈profiler dump 线程栈分析线程持锁情况 问题 3持续 FullGC 在了解 FullGC 原因之前回顾下 Jvm 的内存相关知识 GC过程 新 new 的对象放在 Eden 区当 Eden 区满之后进行一次 MinorGC并将存活的对象放入 S0当下一次 Eden 区满的时候再次进行 MinorGC并将Eden和 S0 的存活对象对象放入S1然后清空Eden和S0垃圾对象最后交换S0和S1的位置S0 和 S1 始终有一个是空的依次循环第一、二步直到 S0 或者 S1 快满的时候将对象放入 old 区直到 old 区满 或 内存不足以放下晋升对象时 进行 FullGC。 永久代和元空间 JDK1.7 之前 Java 类信息、常量池、静态变量存储在 Perm 永久代类的原数据和静态变量在类加载的时候放入 Perm 区类卸载的时候清理在 JDK1.8 中MetaSpace 代替 Perm 区使用本地内存常量池和静态变量放入堆区一定程度上解决了在运行时生成或加载大量类造成的 FullGC如反射、代理、groovy 等。 回收器 年轻代常用 ParNew复制算法多线程并行 老年代常用 CMS标记清除算法会产生内存碎片并发收集(收集过程中有用户线程产生对象)。 关键常用参数 CMSInitiatingOccupancyFraction表示老年代使用率达到多少时进行 FullGCUseCMSCompactAtFullCollection表示在进行 FullGC 之后进行老年代内存整理避免产生内存碎片。 问题 4线程池满 Java 线程池以有界队列的线程池为例 当新任务提交时如果业务线程 小于corePoolSize核心线程则创建新线程来处理请求。如果业务线程数 等于corePoolSize核心线程数时则新任务被添加到任务队列中直到队列满。当队列满了后会继续开辟新线程非核心线来处理任务但不超过 maximumPoolSize最大线程核心线程非核心线程。当任务队列满了并且已开辟了最大线程数此时又来了新任务ThreadPoolExecutor 会执行拒绝策略。 问题 5NoSuchMethodException 1.jar 包冲突: java 在装载一个目录下所有 jar 包时它加载的顺序完全取决于操作系统。 mvn dependency:tree -Dverbose 分析报错方法所在的 jar 包版本留下新的arthas的 sc -d ClassName 查看 jvm 已加载类信息-XX:TraceClassLoading 输出类的加载顺序可以用来排查 class 的冲突问题 2.同类问题 ClassNotFoundExceptionNoClassDefFoundErrorClassCastException 问题 6JVM生成hs_err_pid开头的文件 JVM 发生内部崩溃必然会生成hs_err_pid开头的文件。 无法申请内存显示commit_memory错误 Current thread (0x00007f3e40013000): JavaThread Unknown thread [_thread_in_vm, id11408, stack(0x00007f3e49983000,0x00007f3e49a84000)]Stack: [0x00007f3e49983000,0x00007f3e49a84000], sp0x00007f3e49a82360, free space1020k Native frames: (Jcompiled Java code, jinterpreted, VvVM code, Cnative code) V [libjvm.so0x9a32da] VMError::report_and_die()0x2ea V [libjvm.so0x497f7b] report_vm_out_of_memory(char const*, int, unsigned long, char const*)0x9b V [libjvm.so0x81fcce] os::Linux::commit_memory_impl(char*, unsigned long, bool)0xfe V [libjvm.so0x820219] os::pd_commit_memory(char*, unsigned long, unsigned long, bool)0x29 V [libjvm.so0x819faa] os::commit_memory(char*, unsigned long, unsigned long, bool)0x2a V [libjvm.so0x99eae9] VirtualSpace::expand_by(unsigned long, bool)0x1c9 V [libjvm.so0x99ec6d] VirtualSpace::initialize(ReservedSpace, unsigned long)0xcd V [libjvm.so0x57962f] CardGeneration::CardGeneration(ReservedSpace, unsigned long, int, GenRemSet*)0x11f V [libjvm.so0x46ceed] ConcurrentMarkSweepGeneration::ConcurrentMarkSweepGeneration(ReservedSpace, unsigned long, int, CardTableRS*, bool, FreeBlockDictionaryFreeChunk::DictionaryChoice)0x5d V [libjvm.so0x57a906] GenerationSpec::init(ReservedSpace, int, GenRemSet*)0x106 V [libjvm.so0x56afe4] GenCollectedHeap::initialize()0x344 V [libjvm.so0x9751aa] Universe::initialize_heap()0xca V [libjvm.so0x976379] universe_init()0x79 V [libjvm.so0x5b1d25] init_globals()0x65 V [libjvm.so0x95dc6d] Threads::create_vm(JavaVMInitArgs*, bool*)0x1ed V [libjvm.so0x639fe4] JNI_CreateJavaVM0x74这一般是因为 Xmx 设置过大超过系统可用内存JVM 申请内存失败。 比如服务器总内存30G 同时运行多个程序, 程序 A 配了10G Xmx, 程序B也配了10G Xmx Linux的交换空间也没有设置如果程序AB用满Xmx的那么可用内存必然低于10G这时如果程序C需要大于10G的内存就很容易发生该错误直接宕机! 解决方案 减少Xmx值使得所有的总和不超过服务器物理内存调整 XmsXmx 详见4.常用参数服务器不要运行其他不必要的程序配置一部分swap空间虚拟内存 hs_err_pid.log分析JVM致命错误日志(hs_err_pid.log)分析 如果找不到hs_err_pid开头的文件那么这个进程的闪退必然是被从外部终止的。 java进程长期内存占用过高系统需要内存使用的时候没有内存Linux的 OOM Killer机制 会干掉最低优先级的内存 检查 /var/log/message /var/log/dmesg或者对应日期文件看看有没有类似下面的内容日志有时间可以判断 如 grep Out of memory /var/log/messages 常见问题汇总 线程池满 rpc 框架线程池满高 RT(响应时间)接口进行线程数限流 应用内线程池满重启可短暂缓解具体还得看问题原因 CPU 高load 高 单机置换或重启可短暂缓解恢复看具体原因集群高且流量大幅增加扩容恢复看具体原因 下游 RT(响应时间)高 限流降级 数据库 死锁kill 死锁线程慢 sql 优化sql或sql 限流 【Mysql】太可怕了,跟踪及解决Mysql死锁原来可以这么简单 四.调优实例1-初窥门径 在日常的Java开发中常见以下问题 内存泄露某个进程突然cpu飙升线程死锁响应变慢 1.浏览量暴增后网站响应速度变慢 问题推测在测试环境测速度比较快但是一到生产就变慢所以推测可能是因为垃圾回收导致的业务线程停顿。 定位通过jstat -gc指令 发现GC次数频率非常高 且GC所占用的时间非常长所以判断是因为GC频率非常高所以导致业务线程经常停顿从而造成网页反应很慢。 解决方案因为网页访问量很高所以对象创建速度非常快导致堆内存容易填满从而频繁GC所以这里问题在于年轻代内存太小所以这里可以增加JVM内存就行了所以初步从原来的2G内存增加到16G内存。 第二个问题增加内存后的确平常的请求比较快了但是又出现了另外一个问题就是不定期的会间断性的卡顿而且单次卡顿的时间要比之前要长很多。 问题推测由于之前的优化加大了内存所以推测可能是因为内存加大了从而导致单次GC的时间变长从而导致间接性的卡顿。 定位还是通过jstat -gc 指令 发现FGC次数变多但是花费在FGC上的时间是非常高的, 根据GC日志 查看到单次FGC的时间有达到几十秒的。 解决方案 因为JVM默认使用的是PSPO的组合PSPO垃圾标记和收集阶段都是STW所以内存加大了之后需要进行垃圾回收的时间就变长了所以这里要想避免单次GC时间过长所以需要使用并发收集器 当前为JDK1.7所以选择CMS垃圾收集器根据之前垃圾收集情况设置了一个预期的停顿的时间上线后网站再也没有了卡顿问题。 2.后台导出数据引发的OOM 问题描述 公司的后台系统偶发性的引发OOM异常堆内存溢出。 因为是偶发性的所以第一次简单的认为就是堆内存不足导致所以单方面的加大了堆内存从4G调整到8G。 但问题依然没有解决只能从堆内存信息下手通过开启了-XX:HeapDumpOnOutOfMemoryError 获得堆内存的dump文件。 VisualVM 对 堆dump文件进行分析通过VisualVM查看到占用内存最大的对象是String对象本来想跟踪着String对象找到其引用的地方但dump文件太大跟踪进去的时候总是卡死而String对象占用比较多也比较正常最开始也没有认定就是这里的问题于是就从线程信息里面找突破点。 通过线程进行分析先找到了几个正在运行的业务线程然后逐一跟进业务线程看了下代码发现有个引起我注意的方法导出订单信息。 因为订单信息导出这个方法可能会有几万的数据量首先要从数据库里面查询出来订单信息然后把订单信息生成excel这个过程会产生大量的String对象。 在订单导出功能测试的过程中发现导出按钮前端居然没有做点击后按钮置灰交互事件结果按钮可以一直点因为导出订单数据本来就非常慢使用的人员可能发现点击后很久后页面都没反应结果就一直点结果就大量的请求进入到后台堆内存产生了大量的订单对象和EXCEL对象而且方法执行非常慢导致这一段时间内这些对象都无法被回收所以最终导致内存溢出。 最终没有调整任何JVM参数只是在前端的导出订单按钮上加上了置灰状态等后端响应之后按钮才可以进行点击然后减少了查询订单信息的非必要字段来减少生成对象的体积然后问题就解决了。 3.单个缓存数据过大导致的系统CPU飚高 系统发布生产后发现CPU一直飚高到600%发现这个问题后首先要做的是定位到是哪个应用占用CPU高通过top 找到了对应的一个java应用占用CPU资源600%。 如果是应用的CPU飚高那么基本上可以定位可能是 锁资源竞争或是频繁GC 造成的。 从GC方向排查如果GC正常的话再从线程方向排查首先使用 jstat -gc PID 指令 打印出GC的信息发现应用在运行了几分钟GC时间就达到了482秒那么问这很明显就 是频繁GC导致的CPU飚高。 定位到了是GC的问题那么下一步就是找到频繁GC的原因了所以可以从2方面定位了可能是哪个地方频繁创建对象或者就是有内存泄露导致内存回收不掉。 使用 jmap -dump 指令 把堆内存信息dump下来看一下 堆内存空间大的慎用这个指令否则会导致应用暂停时间过长因为我们的堆内存空间才2G所以也就没考虑这个问题了。 使用JvisualVM导入dump进行离线分析首先从占用内存最多的对象中查找结果排名第三看到一个业务VO占用堆内存约10%的空间很明显这个对象是有问题的。 通过业务对象找到了对应的业务代码发现该对象是查看新闻资讯信息生成的对象由于想提升查询的效率所以把新闻资讯保存到了redis缓存里面每次调用资讯接口都是从缓存里面获取。 把新闻保存到redis缓存里面这个方式是没有问题的有问题的是新闻的50000多条数据都是保存在一个key里面这样就导致每次调用查询新闻接口都会从redis里面把50000多条数据都拿出来再做筛选分页拿出10条返回给前端。50000多条数据也就意味着会产生50000多个对象每个对象280个字节左右50000个对象就有13.3M这就意味着只要查看一次新闻信息就会产生至少13.3M的对象那么并发请求量只要到10那么每秒钟都会产生133M的对象而这种大对象会被直接分配到老年代这样的话一个2G大小的老年代内存只需要几秒就会塞满从而触发GC。 由于问题是因为单个缓存过大造成的那么只需要把缓存减小就行这里把缓存以页的粒度进行缓存每个key缓存10条作为返回给前端1页的数据每次查询从缓存拿出10条数据就避免了此问题的 产生。 4.CPU经常100% 问题定位 问题分析CPU高一定是某个程序长期占用了CPU资源。 1.找出CPU占用率高的进程。 top 列出系统各个进程的资源占用情况。2.找出该进程里的哪个线程CPU占用率高。 top -Hp 进程ID 列出对应进程里面的线程占用资源情况4.找到对应线程ID后 把线程ID转换为16进制 printf %x\n PID 把线程ID转换为16进制5.jstack PID 打印出进程的所有线程信息过滤出该线程ID对应信息 jstack 进程ID| grep -30 16进制线程ID 6.最后根据线程的堆栈信息定位到具体业务方法,从代码中找到问题所在。 1. 查看是否有线程长时间的watting 或blocked 2. 如果线程长期处于watting状态下 关注watting on xxxxxx说明线程在等待这把锁然后根据锁的地址找到持有锁的线程。5.内存飚高问题定位 分析 内存飚高如果是发生在java进程上一般是因为创建了大量对象所导致持续飚高说明 垃圾回收跟不上对象创建的速度或者内存泄露导致对象无法回。 1.先观察垃圾回收的情况 jstat -gc PID 1000 :查看GC次数时间等信息每隔一秒打印一次。jmap -histo PID | head -20 :查看堆内存占用空间最大的前20个对象类型,可初步查看是哪个对象占用了内存如果GC次数频繁而且每次回收的内存空间也正常那说明对象创建速度过快导致内存一直占用很高如果每次回收的内存非常少那说明可能是因为 内存泄露 导致内存一直无法被回收。 2.导出堆内存文件快照( 堆内存空间大的慎用这个指令否则会导致应用暂停时间过长,我的才2G) jmap -dump:live,formatb,file/home/myheapdump.hprof PID :dump指定Java进程堆内存信息到文件3、使用JvisualVM对dump文件进行离线分析,找到占用内存高的对象再找到创建该对象的代码位置从代码和业务场景中定位问题。 6.数据分析平台系统频繁 Full GC 该平台主要对用户在 App 中行为进行定时分析统计并支持报表导出使用 CMS GC 算法。 发现页面打开经常卡顿通过 jstat 命令发现系统每次 Young GC 后大约有 10% 的存活对象进入老年代。 原因为 Survivor 区空间设置过小每次 Young GC 后存活对象在 Survivor 区域放不下提前进入老年代导致老年代满了后触发Full GC 通过调大 Survivor 区使得 Survivor 区可以容纳 Young GC 后存活对象对象在 Survivor 区经历多次 Young GC 达到年龄阈值才进入老年代。 调整之后每次 Young GC 后进入老年代的对象稳定运行时仅几百 KbFull GC 频率大大降低。 7.线程锁死/无限等待 表现: 系统无法访问时当前cpu占用非常低 使用 jstack命令输出线程堆栈即可 jstack 进程ID 1.txt 或 jstack -F 进程ID 1.txt 或 jstack -l 进程ID | grep -i -E BLOCKED | deadlock或者用jprofiler工具看堆栈或者其他任何可以拿到堆栈的工具都可以 java的堆栈就是java方法调用的路径可以定位一些简单问题 五.调优实例2-登堂入室 1.CPU 利用率高/飙升 表现 CPU全部占满应用内存达到配置Xmx最大值 常见原因 “内存泄露” 导致对象无法回收从而造成频繁GC。死循环、线程阻塞、io wait等 public class CpuReaper {public static void main(String[] args) {for (int i 0; i 8; i) {new Thread(() - {CpuReaper cpuReaper new CpuReaper();cpuReaper.cpuReaper();}).start();}}public void cpuReaper() {int num 0;long start System.currentTimeMillis() / 1000;while (true) {num num 1;if (num Integer.MAX_VALUE) {log.info(reset);num 0;}if ((System.currentTimeMillis() / 1000) - start 1000) {return;}}} } 第一步定位出问题的线程 方法 1: 传统的方法 1. top 定位CPU占比最高的Java进程ID 还可以使用pwdx pid命令找到业务进程路径进而定位到负责人和项目 2.top -Hp pid 定位CPU占比最高的线程ID 3. printf 0x%x tid 将线程 id 转化 16 进制 printf 0x%x 128170x32114. jstack pid | grep tid 找到线程堆栈 jstack 12816 | grep 0x3211 -A 30方法 2: show-busy-java-threads show-busy-java-threads教程 show-busy-java-threads脚本 这个脚本来自于github上一个开源项目项目提供了很多有用的脚本show-busy-java-threads就是其中的一个。使用这个脚本可以直接简化方法A中的繁琐步骤。如下: wget --no-check-certificate https://raw.github.com/oldratlee/useful-scripts/release-2.x/bin/show-busy-java-threadschmod x show-busy-java-threads ./show-busy-java-threads# 默认从所有运行的Java进程中找出最消耗CPU的5个线程打印出其线程栈 show-busy-java-threads#可以手动指定要分析的Java进程Id以保证只会显示你关心的那个Java进程的信息 show-busy-java-threads -p 指定的Java进程Id show-busy-java-threads -c 要显示的线程栈数方法 3: arthas thread 阿里开源的arthas现在已经几乎包揽了我们线上排查问题的工作提供了一个很完整的工具集。在这个场景中也只需要一个thread -n命令即可。 curl -O https://arthas.gitee.io/arthas-boot.jar # 下载要注意的是arthas的cpu占比和前面两种cpu占比统计方式不同。前面两种针对的是Java进程启动开始到现在的cpu占比情况arthas这种是一段采样间隔内当前JVM里各个线程所占用的cpu时间占总cpu时间的百分比。 具体见官网 arthas使用 Arthas 是阿里巴巴开源的Java 诊断工具基于Java Agent方式使用 Instrumentation修改字节码方式进行 Java 应用诊断 常用命令 dashboard 系统实时数据面板, 可查看线程内存gc 等信息thread 查看当前线程信息查看线程的堆栈如查看最繁忙的前 n 线程getstatic获取静态属性值如 getstatic className attrName 可用于查看线上开关真实值sc查看 jvm 已加载类信息可用于排查 jar 包冲突sm查看 jvm 已加载类的方法信息jad反编译 jvm 加载类信息,排查代码逻辑没执行原因logger查看logger信息更新logger levelwatch观测方法执行数据包含出参、入参、异常等 watch xxxClass xxxMethod {params, throwExp} -e -x 2 watch xxxClass xxxMethod “{params,returnObj}” “params[0].sellerId.equals(‘189’)” -x 2 watch xxxClass xxxMethod sendMsg ‘com.taobao.eagleeye.EagleEyegetTraceId()’ trace方法内部调用时长并输出每个节点的耗时用于性能分析tt用于记录方法并做回放 arthas常见问题解决 第二步:具体问题具体分析 场景1CPU占比最高的都是GC线程 GC task thread#0 (ParallelGC) os_prio0 tid0x00007fd99001f800 nid0x779 runnable GC task thread#1 (ParallelGC) os_prio0 tid0x00007fd990021800 nid0x77a runnable GC task thread#2 (ParallelGC) os_prio0 tid0x00007fd990023000 nid0x77b runnable GC task thread#3 (ParallelGC) os_prio0 tid0x00007fd990025000 nid0x77c runnable当发生内存溢出的时候或快要内存溢出的时候JVM 发现内存不够就会 GC所有 GC线程开始工作暂停 JVM 运行如果回收到内存了JVM正常执行 如果执行GC没有回收到什么内存GC会循环持续执行这就导致了cpu全部占满的现象所以说内存溢出的时候一定伴随cpu占满“ 场景2CPU占比最高的都是业务线程 iowait等待 IO vmstat 查看 blocked 进程状况jstack -l pid | grep BLOCKED 查看阻塞状态线程堆栈 等待内核态锁如 synchronized jstack -l pid | grep -i -E BLOCKED | deadlock 查看阻塞状态线程堆栈 profiler dump 线程栈分析线程持锁情况 使用arthas的thread -b指令查询当前阻塞其他线程的线程。 2.频繁 GC GC处理过程 解决方案 查看gc日志jstat -gcutil {进程号} {统计间隔毫秒} {统计次数}默认代表一直统计) HotSpot JVM有一类特别的参数叫做可管理的参数可以在运行时动态修改。 通过JDK自带的jinfo工具修改 (如“PrintGC”开头的都是动态参数可以在运行时开启或是关闭GC日志。)通过JMX客户端调用HotSpotDiagnostic MXBean的setVMOption方法来设置这些参数。通过arthas的vmoption命令更新VM诊断相关的参数 获取到gc日志之后可以上传到GC easy帮助分析得到可视化的图表分析结果。 GC 原因及定位(常见问题 3持续 FullGC) 晋升老年代失败 从survivor区晋升的对象在老年代也放不下导致 FullGCFGC 回收无效则抛 OOM。 可能原因 survivor 区太小对象过早进入老年代 查看 SurvivorRatio 参数 java -XX:PrintFlagsFinal -version | grep SurvivorRatio 大对象分配没有足够的内存dump堆快照使用 jhat/JProfiler/MAT 分析对象占用情况老年代存在大量对象dump堆快照使用jhat/JProfiler/MAT 分析对象占用情况 你也可以从Full GC 的效果来推断问题 正常情况下一次Full GC应该会回收大量内存所以 「正常的堆内存增长曲线应该是呈锯齿形」。 如果你发现Full gc 之后堆内存几乎没有下降那么可以推断 「堆中有大量不能回收的对象且在不停膨胀使堆的使用占比超过Full GC的触发阈值但又回收不掉导致Full GC一直执行。「换句话来说可能是」内存泄露」了。 一般来说GC相关的异常推断都需要涉及到「内存分析」使用jmap之类的工具dump出堆内存快照或者 Arthas的heapdump命令然后使用MAT、JProfiler、JVisualVM等可视化内存分析工具。 问题原因及定位 1. 晋升老年代失失败从S区晋升的对象在老年代也放不下导致 FullGCFGC 回收无效则抛 OOM。原因 survivor 区太小对象过早晋升老年代 查看 Survivor区占比 java -XX:PrintFlagsFinal -version | grep SurvivorRatiojstat -gcutil pid 1000 观察内存运行情况jinfo pid 查看 SurvivorRatio 参数 大对象分配没有足够的内存 GC日志查找关键字 “allocating large”dump堆快照然后使用 jhat/JProfiler/MAT 分析大对象分布情况 老年代存在大量对象 实例数量前十的类jmap -histo pid | sort -n -r -k 2 | head -10实例容量前十的类jmap -histo pid | sort -n -r -k 3 | head -10dump堆内存快照使用jhat/JProfiler/MAT 分析对象占用情况 2.concurrent mode failedCMS并发收集失败在 CMS GC 过程中业务线程将对象放入老年代并发收集的特点内存不足。原因 FGC 触发比例过大导致老年代占用过多并发收集时用户线程持续产生对象导致达到触发 FGC 比例。 jinfo pid 查看 CMSInitiatingOccupancyFraction 参数一般 70~80 即可 老年代存在内存碎片。 jinfo pid 查看 UseCMSCompactAtFullCollection参数在 FullGC 后整理内存 你也可以从Full GC 的效果来推断问题 正常情况下一次Full GC应该会回收大量内存所以 「正常的堆内存曲线应该是呈锯齿形」。 如果你发现Full gc 之后堆内存几乎没有下降那么可以推断 「堆中有大量不能回收的对象且在不停膨胀使堆的使用占比超过Full GC的触发阈值但又回收不掉导致Full GC一直执行。「换句话来说可能是」内存泄露」了。 一般来说GC相关的异常推断都需要涉及到「内存分析」使用jmap之类的工具dump出堆内存快照或者 Arthas的heapdump命令然后使用MAT、JProfiler、JVisualVM等可视化内存分析工具。 问题原因及定位 1.下游 RT 高超时时间不合理 业务监控sunfireeagleeye 2 数据库慢 sql 或者数据库死锁 日志关键字 “Deadlock found when trying to get lock”jstack -l pid | grep BLOCKED 或 zprofiler 查看阻塞态线程 【Mysql】太可怕了,跟踪及解决Mysql死锁原来可以这么简单 3 Java 代码死锁 jstack –l pid | grep -i –E BLOCKED | deadlockdump thread 通过 zprofiler 分析阻塞线程和持锁情况 相关好文 彻底理解对象内存分配及Minor GC和Full GC全过程 如何优化生产环境的Full GC 阿里二面说说JVM的Stop the World JVM调优之GC调优——吞吐量优先二 JVM调优之GC调优——响应时间优先三 【JVM进阶之路】七垃圾收集器盘点 JVM-09自动内存管理机制【内存分配和回收策略】 JVM - G1初探
http://www.pierceye.com/news/771951/

相关文章:

  • 温州网站推广外包推推蛙网站建设
  • 北京百度网站排名优化四川公共资源交易网招标网
  • 上海网站制作商多用户网上商城
  • 四川建设网电子招投标网站莱芜金点子电话
  • 深圳科技网站建设网站怎么做跳站
  • 做网站需要多少人全国物流货运平台
  • 温州建网站用自己的电脑做网站
  • 综合性门户网站有哪些高端网站建设 房产
  • 百度做的网站能优化吗如何在jsp上做网站页面代码
  • 广州市品牌网站建设公司营销型网站开发推广
  • 甜品网站首页设计用php做的网站模版
  • 怎样做企业的网站百度下载安装免费版
  • 常州市网站优化汕头网站建设和运营
  • wordpress 同分类评论调用seo排名是什么
  • 网站建设推广怎么玩软件开发模型是什么
  • 网站开发报价表格海口注册公司代理公司地址电话
  • 西宁好的网站建设视频网站文案
  • 郑州网站优化网络建设有限公司网站建设 交单流程
  • 网站搬家内页打不开重庆市建设工程信息网怎么进不去
  • 深圳 做公司网站网站用什么建设
  • 网站更换空间对优化的影响营销号视频生成器手机版
  • 南宁大型网站推广公司昆山网站制作哪家好
  • 格尔木哪里有做网站的wordpress编辑器排版
  • 怎样开电商襄阳抖音seo找哪家
  • 个人网站 域名舞阳专业做网站
  • 做国外购物网站凤山网站seo
  • 苏州制作网站的有几家WordPress文章编辑链接
  • 免费看电视剧的网站2021网站建设坂田
  • 网站建设中 目录怎么做更好wordpress最好用的虚拟主机
  • 网站百度网盘南京市建设局网站