专业的编程技术博客社区

网站首页 > 博客文章 正文

JVM入门第2部分-调试内存问题(jvm内存调优方法)

baijin 2024-09-18 12:10:31 博客文章 4 ℃ 0 评论

在这篇文章中,我们将介绍基于JVM的应用程序的内存问题症状,我们可以使用哪些工具来诊断它们以及如何修复它们。

症状

以下是一些内存问题的症状:

  1. 应用程序性能差

  2. 内存使用异常

  3. OutOfMemory错误(OOME)

糟糕的应用性能

  1. 应用程序未达到预期水平

  2. 响应时间长

  3. 删除客户端请求

  4. 卡住的线程

  5. 服务不可用

  6. 应用程序日志中的时间戳差距较大

内存问题的原因:

  1. 配置错误的内存

  • 旧一代内存空间的尺寸小于实时对象集。这会触发主要的垃圾收集(GC),导致更大的暂停。

  • 代码缓存小于生成的编译代码封装

  • 年轻一代的体型不合适导致过早提升对象

  • PermGen / Metaspace的大小不正确,导致完整的GC

  1. 内存泄漏 - 无意中保留内存空间中的对象

  • 无意引用堆中的对象集

  • 不要取消引用类似于classky的类加载器实例

  • 不适当地释放本地资源

  1. 终结者过度使用

  • 终结者的对象可能会延迟他们自己的GC

  • Finalizer线程在回收它们之前需要调用实例的finalize()方法

  • 只能有1个Finalizer线程。如果它跟不上对象可用于最终化的速度,那么JVM会因OOME而失败

  • 挂起终结器对象基本上是累积垃圾

  • Java 9中已弃用终结器

  1. 显式GC调用

  • System.gc() 并且诊断数据收集可能会导致长时间停顿

  • -XX:+DisableExplicitGC 可以禁用System.gc()调用

  • -XX:+PrintClassHistogram接收kill -3

  • 信号时也会调用显式GC

OutOfMemoryError

层次结构:Throwable->Error->VirtualMachineError->OutOfMemoryError(未经检查的异常)

  • JVM在各种内存空间中运行空间不足或无法继续执行进程时抛出。一些可能性:

  • 本地空间用于Java线程堆栈,加载的jar,zip,本地库,本地资源(如文件); 从本地代码分配的mem

  • 无法分配更多本机内存或创建新线程或本机内存泄漏

  • 在64位计算机上运行32位JVM会限制进程大小4 GB

  • Java堆的位置可以限制本地堆的最大大小。可以通过选项-XX控制:HeapBaseMinAddress = n指定地址本机堆应该基于

  • 完整的GC被调用,但无法释放Metaspace中的空间,应用程序正试图加载更多的类

  • Metaspace默认为“无限”,但可以由MaxMetaspaceSize控制。默认情况下,为压缩类空间保留1 GB

  • 确保-Xnoclassgc未被使用,因为它阻止卸载类

  • 声称空间非常少的GC太多

  • 应用程序线程没有获得任何CPU周期

  • JVM已经调用完整的GC,但无法释放空间

  • 堆的尺寸可能小于应用程序的尺寸,或者应用程序不必要地持有堆中的某些对象

  • 堆空间已满

  • GC超出限制

  • 请求的阵列大小超过VM限制

  • PermGen空间/ Metaspace /压缩类空间

  • 本机内存 - 使用本地方法进行交换空间/堆栈跟踪

CodeCache警告

  • 由JVM打印的警告消息说CodeCache已满,编译器已被禁用。

  • 代码缓存已满时无OOME

  • Sweeper进行紧急清理。这可能会丢弃已编译的代码,JIT可能需要再次执行优化

  • 使用ReservedCodeCacheSize选项确保合适的CC大小

直接缓冲存储器

  • ByteBuffer.allocateDirect(N) :使用幻影引用和引用队列进行垃圾回收的直接缓冲区

  • 默认情况下内存不受限制,但可以通过-XX:MaxDirectMemorySize = n进行控制

  • Java NIO使用。用于I / O的堆ByteBuffer使用临时直接ByteBuffer

诊断数据,数据收集和分析工具

内存泄漏故障排除

  1. 确认内存泄漏

  • 随时监控堆的使用情况

  • 如果完整的GC无法在OldGen中声明空间,可能是配置问题

  • 堆大小可能太小 - >增加堆大小和监视器!如果问题依然存在,则可能是内存泄漏

  • -XX:+GCTimeLimit 设置GC可花费的时间总量的时间上限,默认为98%

  • -XX:+GCHeapFreeLimit GC应释放的空间量设置下限,表示为最大堆的百分比,默认值为2%

  • OutOfMemoryError如果之前的5个连续GC不能保持GC成本低于GCTimeLimit或至少GCHeapFreeLimit空间释放,则在全GC之后抛出

  • PermGen/MetaspaceMetaspace如果频繁的Full GC不要求任何空间,可能会太小

  1. 诊断数据和分析

  • 本机内存跟踪器输出 - 跟踪JVM内部使用的本机内存,而不是外部库。用NativeMemoryTracking选项启动JVM

  • pmaplibumemvalgrind,核心文件

  • 使用JConsole,jmap收集数据

  • 使用堆转储使用Eclipse MAT / Visual VM进行分析

  • 启用堆统计。可以引入额外的性能开销

  • 要创建一个航班记录: -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:StartFlightRecording=delay=20s,duration=60s,name=Rec,filename=lol.jfr,settings=profile

  • 飞行记录可以找出泄漏物体的类型,但是您需要堆转储才能找出造成物体泄漏的原因

  • 收集使用:

  • -XX:+PrintClassHistogramSIGQUIT在Posix和SIGBREAKWindows上

  • jcmd pid GC.class_histogram filename=histo

  • jmap -histo pid core_file

  • jhsdb jmap (Java 9)

  • 我们可以通过以下方式进行堆转储:

  • Eclipse内存分析工具(MAT)显示泄露嫌疑人,直方图,不可达对象,重复类,GC根的引用链,允许使用OQL来探索堆转储。

  • JMCJava VisualVM的JOverFlowYourKit(商业分析器)都可以进行堆转储。

  • jcmd pid GC.heap_dump heapdump.dmp

  • jmap -dump:format = b,file = snapshot.jmap pid

  • 使用MBean HotSpotDiagnostic的JConsole或Java Mission Control

  • OOM错误上的JVM选项堆转储:-XX:+ HeapDumpOnOutOfMemoryError。频繁的完整GC可能会延迟收集堆转储和重新启动进程

  • 对于Java 9+,G1选项是:-Xlog:gc*,gc+phases=debug:file=gc.log . For non G1, -Xlog:gc*:file=gc.log。对于较旧的JVM,-XX:+PrintGCDetails, -XX:+PrintGCTimeStamps, -XX:+PrintGCDateStamps, -Xloggc:gc.log

  • 为了检查metaspace,-verbose:class或者-XX:+TraceClassLoading , -XX:+TraceClassUnloading

  • 我们可以通过人工检查,GCViewer,GCHisto,gceasy.io分析日志

  • GC日志有助于确定堆需求,找出过多的GC和较长的GC暂停以及配置内存空间

  • 堆转储有助于确定意外的内存增长和内存泄漏。

  • 堆直方图 - 快速查看堆中的对象

  • Java飞行记录 - 意外的内存增长和内存泄漏,GC事件

  • 终结

  • 本机内存

结论

在这个系列中,我们看看了JVM如何管理内存以及垃圾收集过程如何工作。我们还了解了如何诊断内存问题,哪些工具可用于收集和分析诊断信息以及可能影响应用程序性能的一些JVM选项。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表