• 1. JVM内存问题最佳实践 JVM Best Practice曾凡光 2010年03月
  • 2. JVM内存问题最佳实践本次技术交流,涵盖范围为: 如何选择合适的Java虚拟机 了解Java基本内存管理基本概念 了解发生内存不足/内存泄漏错误的原因和症状 了解如何诊断内存不足/内存泄漏错误 了解如何解决内存不足/内存泄漏错误
  • 3. 3MENU 选择合适的Java虚拟机 Java内存管理的基本概念 GC次数过多消耗时间过长的原因和症状 内存不足和内存泄漏错误的原因和症状 诊断、定位和解决内存不足和内存泄漏错误 使用分析工具解决内存不足和内存泄漏错误 预防内存不足和内存泄漏 OutOfMemory错误实例
  • 4. 4Java虚拟机的种类Oracle Java虚拟机 原Sun Java虚拟机 原BEA JRockit 两种Java虚拟机,都运行在Windows、Linux、Solaris平台 HP Java虚拟机: 与SUN JDK基本兼容,有自己独特的启动参数 运行在HP UNIX上 IBM Java虚拟机: 与Sun JDK基本兼容 启动参数的写法风格与Sun JDK、HP JDK非常不同 主要用于WebSphere、跑在AIX上的中间件服务器 开源 Java虚拟机: 与SUN JDK兼容
  • 5. 5如何选择合适的Java虚拟机选择稳定的JDK: 刚刚GA的版本不稳定,比如1.5.0_00 1.6.0_00 刚增加新特性的版本不稳定,比如1.5.0_07 1.6.0_14 安装JDK之前,先看厂商的Release Notes 根据平台和应用,选择合适厂商的JDK: HP-UX只能选择HP JDK,AIX只能选择IBM JDK Windows、Linux可以选择SUN JDK和JRockit Solaris平台,最好使用SUN JDK 开源JDK,目前生产环境中用的极少
  • 6. 6Java虚拟机 32 VS 64尽量选择使用32位JDK: 32位JDK在TPS测试中,结果比64位JDK要好;JDK 6.0启用指针压缩技术后,64位略微领先32位JDK 主要适用于内存需求较小,CPU密集型应用 64位JDK主要用于大内存应用: 突破4G内存限制 吞吐量并没有提高 主要用于大内存需求的系统 尽量启用指针压缩技术 IBM: -Xcompressedrefs SUN:-d64 -XX:+UseCompressedOops BEA:-XXcompressedRefs=true
  • 7. 7小节回顾 Java虚拟机的种类 如何选择合适的Java虚拟机 32bit VS 64bit 在本小节中,我们讲述了以下内容:
  • 8. 8MENU 选择合适的Java虚拟机 Java内存管理的基本概念 GC次数过多消耗时间过长的原因和症状 内存不足和内存泄漏错误的原因和症状 诊断、定位和解决内存不足和内存泄漏错误 使用分析工具解决内存不足和内存泄漏错误 预防内存不足和内存泄漏 OutOfMemory错误实例
  • 9. 9Java内存管理的基本概念Java内存 Java 堆内存(heap) Permanent区(Sun/Hp JDK) Java 堆内存(heap): 是 JVM 用于分配 Java 对象的内存,包含活动对象 和不可用对象 堆大小通常是在服务器启动时使用 java 命令中的 –Xms(最小) –Xmx(最大)标志来定义。 Permanent区: 是Sun JDK和HP JDK用来加载类(class)的专门的内存区 这个区域不归属Java 堆内存(heap)范围 如果Java应用很大,例如类(class)很多,那么建议增大这个区域的大小来满足加载这些类的内存需求 通过–XX:PermSize=***M –XX:MaxPermSize=***M调整
  • 10. 10Java内存管理的基本概念本地内存(native memory): 是 JVM 用于其内部操作的本地内存(非Java内存) JNI 代码和第三方本地模块(例如,本地 JDBC 驱动 程序)也使用本地内存 最大本地内存大小取决于以下因素: 操作系统进程内存大小限制 已经指定用于 Java 堆的内存 进程内存大小: 32位操作系统,理论最大值2的32次方=4G 64位操作系统下使用64位的JDK,按照现在的硬件条件,可以看做无限制 进程内存 = Java 内存 + 本地内存 + 加载的可执行文件和库 + 操作系统保留内存
  • 11. 11Java内存管理的基本概念Java堆内存大小的决定因素: 进程大小限制,<=4G “加载的可执行文件和库+系统保留内存”不同操作系统和应用不一样,通常在百M到1G间 JVM的本地内存在不同的JDK之间也不一样。JRockit相对Sun JDK,做了非常好的JIT优化,但是本地内存要求更多的空间 通常Java堆内存大小推荐不大于2G 目前Unix/Linux操作系统默认已经做了内核调整--开启了大内存模式,可以上到2G以上 Java堆内存的大内存模式: AIX上Java堆内存有大内存模式(LAM),最大支持到3.25G Window上有连续地址空间限制,通常不大于1.5G。Windows Advance Server最大支持3G模式。 其他操作系统请查看操作系统文档和对应JVM文档
  • 12. 12物理内存和虚拟内存 进程的虚拟内存由 OS 映射到物理内存。 计算机的物理内存 = RAM + 交换空间 进程 A 的虚拟内存 保留供 OS 使用 Java 堆 本地内存 可执行 文件/库进程 B 的虚拟内存 保留供 OS 使用Java 堆本地内存可执行 文件/库 进程的虚拟内存受 OS 进程 大小的限制。 进程 C 的虚拟内存 可执行 文件/库Java 堆保留供 OS 使用本地内存 进程 D 的虚拟内存 可执行 文件/库 Java 堆保留供 OS 使用本地内存 RAM交换空间 JVM 启动时将保留堆
  • 13. 13Java内存管理的基本概念垃圾回收 (Garbage Collection, GC): JVM自动检测和释放不再使用的内存。 Java 运行时JVM会执行 GC,这样程序员不再需要显式释放对象。 通常在空闲内存降低到某一水平或内存分配达到某一 数量后自动触发。 各种JDK的垃圾回收都有多种算法和策略 以下OutOfMemory 简称 OOM 以下Memory Leak 简称 ML Heap简称“堆”
  • 14. 14Java内存问题的三种表现形式--1Java内存问题的三种表现形式: GC次数过多,导致占用时间过长 内存不足错误 内存泄漏错误 GC占用时间过长--系统明显感觉比较慢 Heap区、Perm区分配内存总量够用 通过verbose gc、jstat观察,GC占用时间超过总时间的5%甚至更高 内存不足错误--明确显示出java.lang.OutOfMemoryError 没有空闲内存可供 JVM 或本地代码用于分配新对象或内存块 在 Java 堆或本地内存中都可能发生
  • 15. 15Java内存问题的三种表现形式--2内存泄漏错误--没有错误信息,但是内存几乎耗尽 已经分配好的内存或对象,当不再需要,没有得到释放 内存曲线是一条斜向上的曲线 对 Java 堆或本地内存都可能产生这个问题 通常最终的状态就会导致 OOM 错误 通常内存泄漏ML会导致 OOM错误,因此两者的探查方法完全相同!
  • 16. 16Java内存问题的两个主要发生区段Java内存问题的两个主要发生区段: Java内存--包括heap堆内存和permanent区 本地内存--包括JVM进程内存和java使用的第三方本地代码 Java内存分配不合理 Java堆内存充足,但是S0、S1、Eden、Old区分配不合理 Perm区-Xms不足 -Xmx充足,类动态加载引起Perm增长导致FULL GC Java内存不足 Java堆内存heap不足,无法再分配新对象或内存块 permanent区内存不足,无法再加载类到内存中(Sun & Hp JDK) 本地内存不足 物理内存不够,无法再得到内存 第三方本地代码有内存泄漏的Bug,例如oracle oci driver本地代码 JVM的JIT或者JVM本身的Bug
  • 17. 17小节回顾 Java进程的内存分类 Java堆内存(Heap) Java Permanent区 Java本地代码 Java内存问题的三个表现类型 Java内存问题的两个发生区段 在本小节中,我们讲述了以下内容:
  • 18. 18MENU 选择合适的Java虚拟机 Java内存管理的基本概念 GC次数过多消耗时间过长的原因和症状 内存不足和内存泄漏错误的原因和症状 诊断、定位和解决内存不足和内存泄漏错误 使用分析工具解决内存不足和内存泄漏错误 预防内存不足和内存泄漏 OutOfMemory/Memory Leak错误实例
  • 19. 19常见GC概念调整GC前提: 程序是健康的 Heap区(-Xmx)够大,日志中没有OutOfMemory异常 花在GC上面的总时间占用太高,比如超过5% 常见GC算法: SUN、HP的GC算法 JRockit的GC算法 IBM JDK的GC算法 GC算法: 选择GC算法的指导思想
  • 20. 20常见GC算法--SUN、HP(1)根据回收器,简单分为: 串行 –XX:+UseSerialGC Out of Box算法,年轻代串行复制,年老代串行标记整理,主要用于桌面应用 并行 –XX:+UseParallelGC 年轻代暂停应用程序,多个垃圾收集线程并行的复制收集,年老代暂停应用程序,与串行收集器一样,单垃圾收集线程标记整理。JDK 6.0启用该算法后,默认启用了-XX:+UseParallelOldGC,性能大为提高 并发(Concurrent Low Pause Collector) –XX:+UseConcMarkSweepGC 启用该参数,默认启用了-XX:+UseParNewGC;简单的说,并发是指用户线程与垃圾收集线程并发,程序在继续运行,而垃圾收集程序运行于其他CPU上。 Garbage First (G1) Garbage Collector -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC SUN JDK 6.0 Update14引入,实际生产环境中还没有采用
  • 21. 21常见GC算法--SUN、HP(2)并行算法示例: -server -Xms1536m -Xmx1536m -XX:NewSize=512m -XX:MaxNewSize=512m -XX:PermSize=128m -XX:MaxPermSize=256m -XX:+UseParallelGC -XX:+UseParallelOldGC -XX:+UseAdaptiveSizePolicy -XX:SurvivorRatio=2 -XX:+DisableExplicitGC -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:/tmp/server_gc$$.log 并发算法示例: -server -Xms1536m -Xmx1536m -XX:NewSize=1024m -XX:MaxNewSize=1024m -XX:PermSize=128m -XX:MaxPermSize=256m -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:SurvivorRatio=2 -XX:MaxTenuringThreshold=16 -XX:+DisableExplicitGC -XX:+CMSPermGenSweepingEnabled -XX:+UseCMSCompactAtFullCollection -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=60 -XX:+CMSParallelRemarkEnabled -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:/tmp/server_gc$$.log
  • 22. 22常见GC算法--JRockit根据回收器,简单分为: -XgcPrio:throughput 默认算法,主要用于桌面应用 -XgcPrio:pausetime -XgcPrio:pausetime -XpauseTarget:210ms 因为免费,所以最低只能设置到200ms。200ms是Real-Time JDK的分界线 -XgcPrio:deterministic 动态调整的垃圾收集策略 示例: -Xms1024m -Xmx1024m -Xgcprio:pausetime -Xpausetarget=210ms -XgcReport -XgcPause -Xverbose:memory
  • 23. 23常见GC算法--IBM根据回收器,简单分为: -Xgcpolicy:optthruput 默认策略。对于吞吐量比短暂的 GC 停顿更重要的应用程序,通常使用这种策略。每当进行垃圾收集时,应用程序都会停顿。 -Xgcpolicy:optavgpause 通过并发地执行一部分垃圾收集,在高吞吐量和短 GC 停顿之间进行折中。应用程序停顿的时间更短。 -Xgcpolicy:gencon 以不同方式处理短期存活的对象和长期存活的对象。采用这种策略时,具有许多短期存活对象的应用程序会表现出更短的停顿时间,同时仍然产生很好的吞吐量。 -Xgcpolicy:subpool 采用与默认策略相似的算法,但是采用一种比较适合多处理器计算机的分配策略。建议对于有 16 个或更多处理器的 SMP 计算机使用这种策略。这种策略只能在 IBM pSeries® 和 zSeries® 平台上使用。需要扩展到大型计算机上的应用程序可以从这种策略中受益。 示例: -Xms768m -Xmx1024m -Xmn256m -Xgcpolicy:gencon
  • 24. 24选择合适的GC算法选择GC算法,遵循以下原则: 评估程序类型 桌面应用还是服务器端应用 吞吐量优先还是响应时间优先 仅适用64位JDK的算法 比如在IBM AIX 64位JDK环境下,当heap区大于16G后,subpool明显性能提高 确定GC算法之后,再逐步调整小参数 -Xmn(-XX:NewSize -XX:MaxNewSize) -XX:SurvivorRatio -XX:MaxTenuringThreshold ....... 测试期间实时监控 SUN、HP、JRockit都可以通过jstat命令进行实时监控 避免使用jmap -histo,原因是可能会造成Full GC
  • 25. 25小节回顾 GC概念 常见GC算法 选择合适的GC算法 在本小节中,我们讲述了以下内容:
  • 26. 26MENU 选择合适的Java虚拟机 Java内存管理的基本概念 GC次数过多消耗时间过长的原因和症状 内存不足和内存泄漏错误的原因和症状 诊断、定位和解决内存不足和内存泄漏错误 使用分析工具解决内存不足和内存泄漏错误 预防内存不足和内存泄漏 OutOfMemory/Memory Leak错误实例
  • 27. 27Java内存问题的主要发生在操作系统本身 Java内存区: heap堆内存 permanent区 本地内存区: JVM进程内存 Java使用的第三方本地代码
  • 28. 28内存不足和内存泄漏错误的典型原因(1)物理内存不足 物理内存有限,例如只有1G 物理内存很大,但是应用很多,占用太多内存 Swap区大小不够 Weblogic Server压力太大 并发用户太多 大数据量分配应用,例如统计报表 Permanent区太小 用户代码内存不释放 http session放置了大量对象 在内存分配大量数据 用户自己创建太多线程 调用AWT等画图接口 用户代码内存泄漏问题 jdbc连接没有close 分配好的对象没有close和释放
  • 29. 29内存不足和内存泄漏错误的典型原因(2)Weblogic Server配置不当 给heap分配的内存太多 session timeout时间太长 EJB pool和Cache的太大 JMS配置 Java内存碎片 尤其在IBM JDK上表现明显 第三方Java应用的内存问题 第三方Java应用也存在内存不足或者泄漏问题 第三方本地代码的内存泄漏问题 第二类JDBC驱动的内存泄漏,例如Oracle Oci Driver 其他第三方本地代码的内存泄漏 JVM本身的内存问题 JIT技术需要消耗更多的本地内存 JVM本身的Bug,例如GC的Bug
  • 30. 30在 Java 堆中发生的 OOM 的故障症状 如果 Java 堆发生 OOM/ML: Weblogic Server运行缓慢,响应速度很慢(JVM在频繁的做GC,Java进程占用比较多的CPU ) 从console的内存监控曲线看,一直徘徊在顶部 最终JVM抛出 java.lang.OutOfMemoryError 异常,stdout 或 stderr 中将显示这则消息 通过thread dump可以看到大部分时间 所有线程都在wait,只有GC线程在工作 很多线程都在申请内存 线程可能会异常退出(即在 Thread Dump 中看不到这个线程,线程丢失) 持续的Java 堆OOM/ML错误偶尔也会导致JVM进程退出服务,通常伴随会产生一个文本Core文件
  • 31. 31在本地内存中发生的 OOM 的故障症状 如果本地内存OOM/ML: Weblogic Server运行缓慢,响应速度很慢 通过操作系统观察可以看到,Java进程内存很大,而且一直在增长 通过console或者GC log可以看到,heap内存通常还有富余 JVM 的通常做法是:处理 OOM 状态,记录消息,然后退出进程。 如果 JVM 或任何其它已加载的模块(例如,libc 或第 三方模块)不处理异常,OS 将通过 sigabort 强制 JVM 退出。 通常会导致JVM异常退出,通常会产生 JVM 文本Core文件和二进制核心文件。
  • 32. 32JVM退出时产生的文本Core文件通常JVM异常退出伴随会产生一个文本Core文件 除了OOM,JVM也会因为其他原因异常退出 IBM JDK -- javacore****.txt文件 Sun & Hp JDK -- hs_err_pid****.log文件 JRockit JDK – jrockit.****.dump文件 文本Core文件包含JVM退出时收到的信号量,并会用*标识导致退出的lib库文件 Signal -1 Signal 0 Signal 4 Signal 10 Signal 11 实践表明,收到以上的信号量,通常但不绝对,表明JVM的内存出现问题 需要结合thread dump或者GC日志来分析
  • 33. 33小节回顾 内存不足和内存泄漏错误的典型原因 OOM 错误的类型及相关故障症状 文本Core文件 在本小节中,我们讲述了以下内容:
  • 34. 34MENU 选择合适的Java虚拟机 Java内存管理的基本概念 GC次数过多消耗时间过长的原因和症状 内存不足和内存泄漏错误的原因和症状 诊断、定位和解决内存不足和内存泄漏错误 使用分析工具解决内存不足和内存泄漏错误 预防内存不足和内存泄漏 OutOfMemory/Memory Leak错误实例
  • 35. 35说在诊断和定位OOM/ML错误之前第一 所有JDK的OOM/ML都是类似的,原理是一样的 诊断定位方法基本一致,除非特殊说明针对那个JDK 这里提及的诊断定位方法以weblogic server为主,但是适用于任何应用服务器(包括tomcat,resin,IAS,websphere) 第二 OOM/ML发生时间跨度大:短的1个小时之内,长的10天甚至1个月 问题解决可能需要耗费大量时间和精力 问题解决经常会反复很多次检查和跟踪 注意保护现场,收集足够多的信息 第三 统计显示 : OOM/ML 问题占2.54%, 但平均处理时间38.5天,数倍于问题平均处理时间
  • 36. 36探查OOM/ML问题基本步骤1)确定是否OOM/ML错误 2)如果保留现场,立即查看 物理内存大小 Java进程内存大小 剩余可用内存大小 Swap区大小 查看GC log 或 进console查看内存使用曲线 并发用户数量/主要业务类型分析 立即做thread dump帮助分析 3)如果没有保留现场,那么 加上GC Flag,收集垃圾回收日志 直到再次发生OOM/ML,分析GC日志 4)基本确定内存问题类型 物理内存不足 并发太多/Java堆内存不足 本地泄漏 其他原因 5)采取相应措施 6)观察,问题是否重现 7)重复定位/问题解决
  • 37. 37确定是否OOM/ML错误明确的OOM/ML错误 是否有明确的OutOfMemory错误信息显示 是否明确的看到内存曲线一直在顶部 是否GC日志明确显示内存紧张 不明确的信息,但是可以归到OOM/ML错误 需要更多信息来证实 GC日志 Thread Dump 文本Core文件 通常可以归到OOM/ML错误的可能症状: Weblogic Server不响应,很慢 GC异常,例如heap使用到顶,GC时间很长 Thread Dump显示几乎所有的线程都在等待,只有GC线程在工作 Core文件指出信号量为-1/0/4/10/11
  • 38. 38查看现场/收集信息(1)物理内存大小 如果物理内存不够,请增加物理内存 Java进程内存大小 如果Java进程内存不大,只有几百M或者1G左右,要结合并发用户和GC日志来考虑 如果Java进程内存特别大,例如到2.5G以上,结合heap设置综合考虑。如果heap设置不大1G左右,那么需要考虑本地内存泄漏的可能 剩余可用内存 结合物理总内存,Java进程内存综合考虑是否合理 Swap区大小 Swap区通常建议是物理内存的2-3倍
  • 39. 39查看现场/收集信息(2)查看GC log 或 进console查看内存使用曲线 并发用户数量/主要业务类型分析 当时并发用户数量以及session大小分析 主要业务类型分析,是否有大内存占用的业务,例如统计报表等等 立即做thread dump帮助分析 每隔30秒做一次,做3次 Unix/Linux : kill -3 pid Windows : Ctrl+break 收集操作系统/JDK/WLS信息 操作系统版本信息 JDK版本信息 WebLogic Server版本信息 是否使用了第三方本地代码
  • 40. 40查看现场/收集信息--措施调整措施 增加物理内存 调整合理的Heap设置 调整Swap区大小 继续跟踪 通过Java进程内存大小和Heap大小判断 Java堆内存问题 本地内存问题 加上GC Flag来分析 IBM JDK -verbose:gc -Xverbosegclog: HP JDK -Xverbosegc[:help]|[0|1][:file=[stdout|stderr|]] -Xloggc Sun JDK / BEA Jrockit -verbose:gc 继续下一步 – 分析GC日志
  • 41. 41分析GC日志--完整 GC 的输出 不同的JDK将产生不同格式GC日志,以下分析以Sun JDK标准GC日志为准 不同的JDK有各自的其他丰富信息的GC开关选项 完整 GC 将产生类似如下内容的消息: [memory ] : GC K->K (K), ms 其中: GC 的开始时间(秒),从 JVM 启动开始计算 回收前对象所使用的内存 (KB) 回收后对象所使用的内存 (KB) 回收后的堆大小 (KB) 执行回收的总时间(毫秒)。 完整 GC 消息示例: [memory ] 7.160: GC 131072K->130052K (131072K) in 1057.359 ms
  • 42. 42分析GC日志--分析 GC 输出 GC 输出可以反映以下情况: OOM 错误是否发生在运行完整 GC 之后 GC 返回了多少空闲空间,GC运行了多长时间 内存使用量是否增加缓慢(即表明发生了内存泄漏,通常需要观察长时间/大量的GC日志) 是否存在内存碎片 结合JVM进程内存大小,判断Java heap内存问题还是本地内存问题
  • 43. 43分析GC日志--确定内存问题类型基本确定内存问题类型 Java堆内存不足 本地内存泄漏 不同内存问题类型,解决方案有所不同 如何确定: Java堆内存不足 Java进程内存比较稳定 GC日志显示,heap区内存不够,GC很频繁 本地内存泄漏 GC日志显示,heap内存尚有足够空间 但是Java进程却随时间一直在增长(需要长时间观察积累)
  • 44. 44处理 Java Heap OOM 错误 对于 Java Heap OOM 错误: 请确保启用 verbose GC,也就是在启动服务器时使用 java -verbosegc 开关 检查 OOM 错误是否发生在运行了完整的 GC 之后 检查是否执行了内存压缩以减少内存碎片 还要留意初始(和周期)JVM 堆可用性/占用率。
  • 45. 45针对 Java 堆 OOM 的应用程序分析 如果 JVM 正确执行了 GC,则应该是应用程序问题所致: 如果应用程序使用了缓存对象: 请确保对缓存对象数量施加了限制 或许可以降低缓存限值来减少总体堆大小 如果应用程序使用了活动时间长的对象,请减少这些对象的数量或缩短它们的生命周期,例如,缩短 HTTP 会话的超时期间 调整垃圾回收策略,可能解决OOM问题 查找内存泄漏,例如,不正确的 JDBC 池连接处理 如果服务器只是对负载增加或添加应用程序作出反应,JVM 自然会需要更大的Heap
  • 46. 46分析GC日志--内存缓慢增长从GC日志中看到内存的缓慢增长 [GC 71678K->61588K(98112K), 0.0073410 secs] [GC 97999K->87826K(98240K), 0.0073438 secs] [GC 190603K->170624K(191640K), 0.0196674 secs] [GC 144325K->121582K(225376K), 0.0850580 secs] [GC 189537K->162596K(257432K), 0.0170420 secs] [GC 239766K->210684K(277080K), 0.0299292 secs] [GC 246611K->208929K(359776K), 0.0172918 secs] …………………
  • 47. 47分析GC日志--内存碎片从GC日志中分析观察到内存碎片现象 这个问题多发生在IBM JDK上,因为它采用的垃圾回收算法跟别的JDK不一致(注:IBM JDK GC输入与上略有不同) 在Sun JDK / HP JDK不常见,很少出现 调整策略 IBM JDK:-Xcompactgc Sun JDK:增加young区大小 -XX:NewRatio -XX:NewSize -XX:MaxNewSize -XX:SurvivorRatio(详细参见Sun文档)GC 减少了使用的堆,其大小已与最大 堆大小有明显差距,OOM 却依然出现! 显示在执行 GC 后仍存在碎片的 GC 消息示例: [memory ] 8.162: GC 73043K->72989K (131072K) in 12.938 ms [memory ] 8.172: GC 72989K->72905K (131072K) in 12.000 ms [memory ] 8.182: GC 72905K->72580K (131072K) in 13.509 ms . . . java.lang.OutOfMemoryError
  • 48. 48分析GC日志--Permanent区不够从GC日志中观察到 这个问题发生在Sun/HP JDK上,因为它采用Permanent区来存放Java的class对象 这个问题的主要区别在于两者发生的时间不一样 调整策略 增加Permanent区大小 -XX:MaxPermSize=256M(推荐128M以上)OOM 却依然出现!注意这种情况主要出现 在WLS启动不久,通常在1-20分钟内。GC日志显示内存还充足 [memory ] 8.162: GC 73043K->72989K (131072K) in 12.938 ms [memory ] 8.172: GC 72989K->72905K (131072K) in 12.000 ms [memory ] 8.182: GC 72905K->72580K (131072K) in 13.509 ms . . . java.lang.OutOfMemoryError
  • 49. 49进一步分析 Java 堆 OOM 如果迄今为止所进行的分析不起作用,请使用 JVM 性能探查工具: 该探查工具将实现 JVM 事件探查器接口 (JVM Profiler Interface, JVMPI),如 Jprobe 或 OptimizeIt或者YourKit 确定占用堆的对象的类型、数量和大小 确定对象在代码中的创建位置 其用法的详细信息,请参考相应的JVM性能探查工具文档 不过,JVM 事件探查器通常需要较高的系统开销, 因此建议一定不要在生产环境中使用! 与应用程序团队合作,查明可能存在的内存泄漏或 改进对象的使用和/或生命周期状况。
  • 50. 50JRockit 功能 JRockit 1.4.2 支持 Java 运行时分析器 (Java Runtime Analyzer, JRA): 该分析器对 JRockit JVM 及 JRockit 上运行的 Java 应用程序都能够进行运行时性能分析。 JRA 包括以下两个部分: 收集有关 JVM 和当前正在运行的 Java 应用程序的数据。 使用分析器工具来查看收集到的信息。 执行几分钟的记录,然后对数据进行分析,以确定具 体的 JVM 问题 JRockit 1.4.2_05 的JRA支持Memory Leak检测功能
  • 51. 51处理本地内存 OOM(1)对于本地内存 OOM 错误: 采用的探查方法与对 Java 堆 OOM 采用的探查方法 相同: 通过 -verbosegc 开关收集 GC 信息 确认 GC 的运行合乎预期,例如,是在 OOM 发生前 运行 留意 JVM 堆的初始(和周期)可用性/占用率。 定期监视进程内存大小: 在 Unix/Linux 上,使用 ps -p -o vsz 或者top命令 在 Windows 上,使用 perfmon 工具。 确定是否使用了任何本地模块或 JNI 代码。 还要检查计算机的物理内存总量(RAM 和交换空间 之和)是否足以满足所有正在运行的进程的需要
  • 52. 52处理本地内存 OOM(2)请记住,进程内存大小: 是进程运行时所占用的地址空间 受 OS 进程大小值的限制: 32 位 Unix:进程大小限值为 4GB,保留 1-2GB 供 OS 自己使用 Red Hat Linux AS 2.1:可供应用程序使用的进程大小为 3GB Windows:进程大小限值为 2GB(缺省值),但可以增加到3GB 包括 Java 堆内存,JVM 在服务器启动时会保留指定的最大值 还可能由 JNI 代码或本地模块(例如,本地 JDBC 驱动程序) 进行分配 还会受计算机物理内存及计算机中运行的其它进程的限制。
  • 53. 53处理本地内存 OOM(3)使用收集到的数据来解决 OOM 错误 如果怀疑发生了内存泄漏,集中精力查找泄漏源 第三方代码(例如,JDBC 驱动程序)或 JNI 代码 可能会发生泄漏 排除法,不使用第三方代码 可能的情况下尝试替换纯 Java 实现,以确认泄漏源。 如果存在本地内存泄漏 增加物理内存,只能够延缓故障发生,无法根除问题
  • 54. 54处理本地内存 OOM(4)从GC日志中看到Heap实际使用大小远小于最大值,可以减少这个最大值,提供更多可用的本地内存 如果 RAM 和交换空间不足,添加内存或者升级计算机 JVM 使用本地内存: 加载类和生成代码,但在启动几小时后,内存使用量通常会稳定下来 可能会发生运行时类加载和代码优化(JIT) 禁用JIT功能: 如果使用的是 JRockit,-Xnoopt 如果使用的是 Sun/HP的JDK,-Xint 如果使用的是 IBM JDK,-Djava.compiler=NONE
  • 55. 55处理本地内存 OOM(5)最后,如果无法查明本地内存 OOM 错误的成因: 请与 JVM 供应商联系,找到跟踪本地内存分配调用的方法 请与第三方模块或 JNI 代码供应商联系,是否有调试/跟踪功能 继续收集和分析有关 OOM 错误发生时间和发生原因的信息 如果存在多个成因,缩小探查范围可能需要一些时间。 升级 升级JDK 升级操作系统 升级Weblogic Server
  • 56. 56小节回顾 如何识别 Java 内存错误和本地内存错误 根据GC日志解决内存问题 解决 Java 内存问题的步骤 解决本地内存问题的步骤 在本小节中,我们讲述了以下内容:
  • 57. 57MENU 选择合适的Java虚拟机 Java内存管理的基本概念 GC次数过多消耗时间过长的原因和症状 内存不足和内存泄漏错误的原因和症状 诊断、定位和解决内存不足和内存泄漏错误 使用分析工具解决内存不足和内存泄漏错误 预防内存不足和内存泄漏 OutOfMemory/Memory Leak错误实例
  • 58. 58使用分析工具来分析OOM问题发生Java Heap OOM 问题时,无法定位到问题,最终的办法只能使用分析工具来做分析。 常用内存分析工具 此类工具非常多,推荐使用轻量级分析工具 YourKit -轻量级 Eeclipse Memory Analyzer -离线分析 IBM Heap Analyzer &MDD4J -离线分析
  • 59. 59YourKit(1)YourKit是一款轻量级的Java运行时分析工具 http://www.yourkit.com 特性: 性能好,对生产系统造成的影响相对其他工具比较小 支持多种平台(windows/linux/mac/solaris) 支持多种JDK(理论上) 界面友好 启动方式: 安装YourKit,启动并加载license 拷贝domain下的启动脚本startWebLogic.cmd或startWebLogic.sh,并重命名为startWLS.cmd/ startWLS.sh 在YourKit中找到startWLS.cmd/ startWLS.sh,得到新的启动脚本startWLS_with_yjp.bat/ startWLS_with_yjp.sh 使用startWLS_with_yjp.bat/ startWLS_with_yjp.sh启动weblogic server,记住启动时YourKit在weblogic server上得到的监听端口 在YourKit中连接到这个监听端口,并开始监控和分析weblogic server的运行情况
  • 60. 60YourKit(2) 启动和配置YourKit 1234
  • 61. 61YourKit(3)使用收集到的数据来解决 OOM 错误 如果YourKit跟WebLogic Server本机运行,选第一项 如果YourKit连接远程的 WebLogic Server,选第二项 需要IP和Port
  • 62. 62YourKit(4)抓取内存镜像SnapShot ,做分析
  • 63. 63Eclipse Memory Analyzer(1)Eclipse Memory Analyzer原名SAP Memory Analyzer,后SA公司捐献给Eclipse社区,现在IBM也加入进来,是目前最实用的免费离线内存诊断工具 特性: 离线分析,不影响生产系统 需要得到JDK内存镜像 支持SUN、HP(1.4.2_12 1.5.0_07及以后版本) 最新版本支持IBM JDK 启动方式: 启动参数增加 -XX:+HeapDumpOnCtrlBreak -XX:+HeapDumpOnOutOfMemoryError Kill -3 得到heapdump文件 JDK5.0可以采用jmap -heap:format=b pidofjava JDK6.0可以采用jmap -dump:live,format=b,file=/tmp/xxx.hprof pidofjava 启动Eclipse Memory Analyzer,加载heapdump文件 图形化分析
  • 64. 64Eclipse Memory Analyzer(2)启动界面
  • 65. 65Eclipse Memory Analyzer(3)Overview视图
  • 66. 66Eclipse Memory Analyzer(4)Leak Suspects视图
  • 67. 67Eclipse Memory Analyzer(5)Dominator tree视图
  • 68. 68Eclipse Memory Analyzer(6)结合使用Leak Suspects和Dominator tree视图
  • 69. 69HeapAnalyzer(1)HeapAnalyzer是一款针对IBM JDK的内存文本镜像HeapDump的分析工具 特性: 离线分析,不影响生产系统 需要得到IBM JDK内存镜像 只支持IBM JDK 只能静态分析,要求得到现场数据 启动方式: Kill -3 得到heapdump文件 启动HeapAnalyzer,加载heapdump文件 图形化分析
  • 70. 70HeapAnalyzer(2)HeapDump是IBM JDK Heap内存的一个文本镜像,默认生成位置在Weblogic Server启动目录下,通常是Domain目录 如果得不到HeapDump,可能是禁止生成 HeapDump的生成开关 export IBM_HEAPDUMP=true export IBM_HEAP_DUMP=true export IBM_HEAPDUMP_OUTOFMEMORY=true export IBM_JAVADUMP_OUTOFMEMORY=true export IBM_JAVACORE_OUTOFMEMORY=true export IBM_HEAPDUMPDIR= 注意: 通常HeapDump会比较大,尤其是在Heap内存设置很大的情况下 为了重现问题,得到现场数据,建议先把HeapDump调小,推荐1G以下 在Window上,如果HeapDump大于1G,可能会无法打开,出现OOM错误 启动HeapAnalyzer需要指定-Xmx参数
  • 71. 71HeapAnalyzer(3)启动界面
  • 72. 72HeapAnalyzer(4)内存按树状引用关系显示
  • 73. 73HeapAnalyzer(5)内存按对象和类型显示
  • 74. 74HeapAnalyzer(6)找到怀疑泄漏的内存对象
  • 75. 75HeapAnalyzer(7)内存碎片分析
  • 76. 76小节回顾 内存分析工具 YourKit Eeclipse Memory Analyzer IBM HeapAnalyzer&MDD4J 在本小节中,我们学习了以下内容:
  • 77. 77MENU 选择合适的Java虚拟机 Java内存管理的基本概念 GC次数过多消耗时间过长的原因和症状 内存不足和内存泄漏错误的原因和症状 诊断、定位和解决内存不足和内存泄漏错误 使用分析工具解决内存不足和内存泄漏错误 预防内存不足和内存泄漏 OutOfMemory/Memory Leak错误实例
  • 78. 78预防内存不足和内存泄漏最好的补救不如事先的预防 预防内存不足和内存泄漏 系统管理 代码编写
  • 79. 79预防内存不足和内存泄漏-系统管理系统管理 足够的物理内存,适当的Swap区大小 最佳的HEAP内存设置 使用最新的操作系统/最新的JDK/最新版本的WLS 使用Weblogic Server认证的JDK 尽量少使用第三方本地代码,或使用Java替代方案 对Sun JDK,合适的Permanent区大小 适当的垃圾回收算法和策略 适当的HttpSession Timeout时间 适当的EJB Pool/Cache 适当的weblogic server调优
  • 80. 80预防内存不足和内存泄漏-代码编写代码编写 不要放置大量对象到Session中 不要缓存太多数据 用完的资源一定要close(),例如IO,File,JDBC连接 不要违反J2EE规范。例如在EJB里开Socket 合理的从数据库取得适量数据 XML解析对大内存的需求 统计和报表业务的负荷问题 良好的代码习惯
  • 81. 81小节回顾 预防内存不足和内存泄漏 系统管理 代码编写在本小节中,我们讲述了以下内容:
  • 82. 82MENU 选择合适的Java虚拟机 Java内存管理的基本概念 GC次数过多消耗时间过长的原因和症状 内存不足和内存泄漏错误的原因和症状 诊断、定位和解决内存不足和内存泄漏错误 使用分析工具解决内存不足和内存泄漏错误 预防内存不足和内存泄漏 OutOfMemory/Memory Leak错误实例
  • 83. 83OutOfMemory错误实例 案 例 一
  • 84. 84OutOfMemory错误实例(1)现象环境IBM AIX 5.2,JDK1.4.2,Weblogic Server 813 刚启动很好,过了一段时间,用户数上来,就发生OOM。自动产生heapdump和javacore文件 只能重启。重启过了一段时间又是这样。
  • 85. 85OutOfMemory错误实例(1)问题 收集什么信息???
  • 86. 86OutOfMemory错误实例(1)答案GC日志 JavaCore文件分析 Thread Dump HeapDump用HeapAnalyser
  • 87. 87OutOfMemory错误实例(1) - GC日志 ********************************************
  • 88. 88OutOfMemory错误实例(1) - Thread Dump1TISIGINFO OUTOFMEMORY received 1TIDATETIME Date: 2005/05/11 at 15:56:13 1TIFILENAME Javacore filename: /bea/user_projects/domains/mydomain/javacore696496.1115798173.txt 1XHTIME Wed May 11 15:56:13 2005 1XHSIGRECV Unexpected signal -1 received at 0x0 in . Processing terminated. 1XHFULLVERSION J2RE 1.4.2 IBM AIX build ca1420-20040626 2CIUSERARG -Xms1024m 2CIUSERARG -Xmx1024m 2CIUSERARG -verbose:gc 2CIUSERARG -Xverbosegclog:/bea/gc.log 1STHEAPFREE Bytes of Heap Space Free: 45b8 (17,848) 1STHEAPALLOC Bytes of Heap Space Allocated: 3ffefa00 (1,073,674,752) 2LKREGMON Heap lock (0x30071788): owner "ExecuteThread: '0' for queue: 'weblogic.socket.Muxer'" (0x7BA1EC20), entry count 2 3LKWAITERQ Waiting to enter: 3LKWAITER "ExecuteThread: '2' for queue: 'weblogic.kernel.Non-Blocking'" (0x7DF83CA0) 3LKWAITER "ListenThread.Default" (0x7D9D78A0) 3LKWAITER "weblogic.health.CoreHealthMonitor" (0x7C6E3320) 3LKWAITER "Thread-5" (0x7C25BC20) 3LKWAITER "ExecuteThread: '2' for queue: 'weblogic.admin.RMI'" (0x7BD332A0) 3LKWAITER "ExecuteThread: '0' for queue: 'weblogic.admin.RMI'" (0x7BD298A0) 3LKWAITER "ExecuteThread: '2' for queue: 'weblogic.socket.Muxer'" (0x7BA1FEA0) 3LKWAITER "ExecuteThread: '1' for queue: 'weblogic.socket.Muxer'" (0x7BA1F8A0) 3LKWAITER "ExecuteThread: '149' for queue: 'weblogic.kernel.Default'" (0x7B4AE3A0) 3LKWAITER "ExecuteThread: '143' for queue: 'weblogic.kernel.Default'" (0x7B180920) 3LKWAITER "ExecuteThread: '142' for queue: 'weblogic.kernel.Default'" (0x7B0F8F20) 3LKWAITER "ExecuteThread: '128' for queue: 'weblogic.kernel.Default'" (0x7A98E6A0) 3LKWAITER "ExecuteThread: '127' for queue: 'weblogic.kernel.Default'" (0x7A906D20) 3LKWAITER "ExecuteThread: '122' for queue: 'weblogic.kernel.Default'" (0x7A660C20) 3LKWAITER "ExecuteThread: '107' for queue: 'weblogic.kernel.Default'" (0x79E6EA20) 3LKWAITER "ExecuteThread: '100' for queue: 'weblogic.kernel.Default'" (0x79AB6420) 3LKWAITER "ExecuteThread: '99' for queue: 'weblogic.kernel.Default'" (0x79A2EA20) 3LKWAITER "ExecuteThread: '98' for queue: 'weblogic.kernel.Default'" (0x799A70A0)
  • 89. 89OutOfMemory错误实例(1) - Thread Dump 3XMTHREADINFO "ExecuteThread: '81' for queue: 'weblogic.kernel.Default'" (TID:0x30106330, sys_thread_t:0x790A5AA0, state:CW, native ID:0x5B5C) prio=5 4XESTACKTRACE at java.lang.Object.wait(Native Method) 4XESTACKTRACE at java.lang.Object.wait(Object.java:443) 4XESTACKTRACE at weblogic.kernel.ExecuteThread.waitForRequest(ExecuteThread.java:153) 4XESTACKTRACE at weblogic.kernel.ExecuteThread.run(ExecuteThread.java:172) 3XMTHREADINFO "ExecuteThread: '98' for queue: 'weblogic.kernel.Default'" (TID:0x30105890, sys_thread_t:0x799A70A0, state:MW, native ID:0x6C6D) prio=5 4XESTACKTRACE at java.lang.String.substring(String.java(Compiled Code)) 4XESTACKTRACE at java.lang.String.substring(String.java(Compiled Code)) 4XESTACKTRACE at weblogic.servlet.internal.WarClassFinder.getSource(WarClassFinder.java(Compiled Code)) 4XESTACKTRACE at weblogic.servlet.internal.WebAppServletContext.getSource(WebAppServletContext.java(Compiled Code)) 4XESTACKTRACE at weblogic.servlet.internal.WebAppServletContext.getResourceAsSource(WebAppServletContext.java(Compiled Code)) 4XESTACKTRACE at weblogic.servlet.internal.WebAppServletContext.getResourceAsSource(WebAppServletContext.java(Compiled Code)) 4XESTACKTRACE at weblogic.servlet.internal.WebAppServletContext.isResourceStale(WebAppServletContext.java(Compiled Code)) 4XESTACKTRACE at jsp_servlet._feebyowner.__search_result._isStale(__search_result.java(Compiled Code)) 4XESTACKTRACE at weblogic.servlet.jsp.JspStub.isServletStale(JspStub.java(Compiled Code)) 4XESTACKTRACE at weblogic.servlet.internal.ServletStubImpl.isStale(ServletStubImpl.java(Compiled Code)) 4XESTACKTRACE at weblogic.servlet.jsp.JspStub.checkForReload(JspStub.java(Compiled Code)) 4XESTACKTRACE at weblogic.servlet.internal.ServletStubImpl.getServlet(ServletStubImpl.java(Compiled Code)) 4XESTACKTRACE at weblogic.servlet.internal.ServletStubImpl.invokeServlet(ServletStubImpl.java(Compiled Code))
  • 90. 90OutOfMemory错误实例(1) - 分析 问题在哪里???
  • 91. 91OutOfMemory错误实例(1)分析用户没有估计到报表业务的内存需求量 用户调整报表业务的实现方式和技术方案
  • 92. 92OutOfMemory错误实例 案 例 二
  • 93. 93OutOfMemory错误实例(2)现象环境Windows 2003,JDK1.5.0_22 32bit,Weblogic Server 9.2 MP3 刚刚启动,运行非常正常 过了一段时间(不定),Weblogic Server抛出OOM异常 。 从GC日志中看到,Heap区在极短时间内被占光 物理系统足够,空闲内存足够
  • 94. 94OutOfMemory错误实例(2)问题 收集什么信息???
  • 95. 95OutOfMemory错误实例(2)答案GC日志 系统参数,采用的第三方组件 用性能检测工具分析 用Eeclipse Memory Analyzer进行离线分析
  • 96. 96OutOfMemory错误实例(3) - 分析 问题在哪里???
  • 97. 97OutOfMemory错误实例(3)过程和结果用Eeclipse Memory Analyzer分析显示: 内存中存在apache的poi excel处理组件 根据业务系统的需要,升级到64位WebLogic 9.2 MP3,问题解决
  • 98. 98小节回顾 两个OOM/ML解决实例在本小节中,我们讲述了以下内容:
  • 99. 99回顾 内存不足/内存泄漏的基本概念 诊断和定位内存问题 故障排除步骤和方案 应用分析工具解决问题 OOM/ML实例在本次Webinar中,我们讲述了以下内容: