JVM内存Dump原理与在线分析实战 | 得物技术

限时加码!20+主流AI编程工具免费用 购周边加赠Coding Plan Lite,Claude Code、Cursor等即刻畅享,学习进阶更高效! 阅读详情

1.前言

当前我们微服务容器化部署JVM 实例很多,常常需要进行JVM heap dump analysis,为了提升JVM 问题排查效率,得物技术保障团队研究了JVM内存Dump 原理与设计开发了JVM 内存在线分析。

常见的JVM  heap dump analysis 工具如: MAT,JProfile,最常用的功能是大对象分析。功能上本地分析工具更全面,在微服务架构下,成千上万的实例当需要一次分析的时候,于是我们思考如何提供更方便更快的在线分析方便研发人员快速排障。

流程

传统

在线分析

相比

hprof 获取

jmap

jmap

相同

hprof 传输

1.上传ftp或对象存储。

2.生产环境涉及跨网脱敏。

3.跨网下载。

内网OSS(对象存储)传输。

目前jvm 基本进入G1 大内存时代。越大内存dump 效果越明显耗时降低(100倍耗时降低)为大规模dump分析打下基础。

hprof 分析

本地MAT 、JProfiler等分析工具

在线分析、在线分析报告

优点:

  1. 不依赖任何软件。

  2. 操作简单,只需一键执行脚本。

  3. 分析耗时比本地工具更快。

  4. 不受内存限制,支持大内存dump 分析。

  5. 自研不受商业限制。

  6. 微服务环境多实例同时并发分析,不受单机资源限制。

不足:

  1. MAT ,JProfile 功能更丰富

2.JVM 内存模型

首先我们快速过一下Java 的内存模型, 这部分不必深入,稍微了解不影响第三部分 JVM 内存分析原理。可回过头来再看。

JVM 内存模型可以从共享和非共享理解,也可以从 stack,heap 理解。GC 主要作用于 heap 区, stack 的内存存在系统内存。

2.1 Run-Time Data Areas

Java 程序运行起来后,JVM 会把它所管理的内存划分为若干个不同的数据区域。其中一些数据区是在 Java 虚拟机启动时创建的,只有在 Java 虚拟机退出时才会销毁。其他数据区是每个线程。每线程数据区在创建线程时创建,并在线程退出时销毁。JVM 的数据区是逻辑内存空间,它们可能不是连续的物理内存空间。下图显示了 JVM 运行时数据区域:

  • PC Register

JVM 可以同时支持多个执行线程。每个 JVM 线程都有自己的 pc(程序计数器)寄存器。如果当前方法是 native方法则PC值为 undefined, 每个CPU 都有一个 PC,一般来说每一次指令之后,PC 值会增加,指向下一个操作指令的地址。JVM 使用PC 保持操作指令的执行顺序,PC 值实际上就是指向方法区(Method Area) 的内存地址。

  • JVM Stacks

每个 JVM 线程都有一个私有 JVM Stack(堆栈), 用于存储 Frames(帧)。JVM Stack的每一Frame(帧)都存储当前方法的局部变量数组、操作数堆栈和常量池引用。

一个 JVM Stack可能有很多Frame(帧),因为在线程的任何方法完成之前,它可能会调用许多其他方法,而这些方法的帧也存储在同一个 JVM Stack(堆栈)中。

JVM Stack 是一个先进后出(LIFO)的数据结构,所以当前的执行方法位于栈顶,每一个方法开始执行时返回、或抛出一个未捕获的异常,则次frame 被移除。

JVM Stack 除了压帧和弹出帧之外,JVM 堆栈从不直接操作,所以帧可能是堆分配的。JVM 堆栈的内存不需要是连续的。

  • Native Method Stack

Native 基本为C/C++ 本地函数,超出了Java 的范畴,就不展开赘述了。接入进入共享区域Heap 区。

2.2 Heap

JVM 有一个在所有 JVM 线程之间共享的堆。堆是运行时数据区,从中分配所有类实例和数组的内存。

堆是在虚拟机启动时创建的。对象的堆存储由自动存储管理系统(称为垃圾收集器)回收;对象永远不会被显式释放。JVM 没有假设特定类型的自动存储管理系统,可以根据实现者的系统要求选择存储管理技术。堆的内存不需要是连续的。

  • Method Area

JVM 有一个在所有 JVM 线程之间共享的方法区。方法区类似于常规语言编译代码的存储区,或类似于操作系统进程中的“文本”段。它存储每个类的结构,例如运行时常量轮询、字段和方法数据,以及方法和构造函数的代码,包括在类和实例初始化和接口初始化中使用的特殊方法。

Method 区域是在虚拟机启动时创建的。尽管方法区在逻辑上是堆的一部分,但简单的实现可能会选择不进行垃圾收集或压缩它。方法区可以是固定大小,也可以根据需要进行扩展。方法区的内存不需要是连续的。

  • Run-Time Constant Pool

运行时常量池是方法区的一部分。Claas 文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译期生成各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。

2.3 Thread

Java 程序最终运行的主体是线程,那么JVM 运行时数据区可以按线程间是否共享来划分:

  • 单个线程内共享的区: PC Register、JVM Stacks、Native Method stacks。

  • 所有线程共享的区: Heap、Method Area、Run-time Constant pool。

  • Pre-Threads:

  • JVM System Threads

  • Per Thread

  • Program Counter

  • Stack

  • Native Stack

  • Stack Restrictions

  • Frame

  • Local Variables Array

  • Operand Stack

  • Dynamic Linking

  • JVM System Threads

如果你使用jconsole或者其他任何debug工具,有可能你会发现有大量的线程在后台运行。这些后台线程随着main线程的启动而启动,即,在执行public static void main(String[])后,或其他main线程创建的其他线程,被启动后台执行。

Hotspot JVM 主要的后台线程包括:

  • VM thread: 这个线程专门用于处理那些需要等待JVM满足safe-point条件的操作。safe-point代表现在没有修改heap的操作发生。这种类型的操作包括:”stop-the-world”类型的GC,thread stack dump,线程挂起,或撤销对象偏向锁(biased locking revocation)

  • Periodic task thread: 用于处理周期性事件(如:中断)的线程

  • GC threads: JVM中,用于支持不同阶段的GC操作的线程

  • Compiler threads: 用于在运行时,将字节码编译为本地代码的线程

  • Signal dispatcher thread: 接受发送给JVM处理的信号,并调用对应的JVM方法

  • Program Counter (PC)

当前操作指令或opcode的地址指针,如果当前方法是本地方法,则PC值为undefined。每个CPU都有一个PC,一般来说,每一次指令之后,PC值会增加,指向下一个操作指令的地址。JVM使用PC保持操作指令的执行顺序,PC值实际上就是指向方法区(Method Area)中的内存地址。

  • Stack

每一个线程都拥有自己的栈(Stack),用于在本线程中正在执行的方法。栈是一个先进后出(LIFO)的数据结构,所以当前的执行方法位于栈顶。每一个方法开始执行时,一个新的帧(Frame)被创建(压栈),并添加到栈顶。当方法正常执行返回,或方法执行时抛出一个未捕获的异常,则此帧被移除(弹栈)。栈,除了压栈和弹栈操作外,不会被执行操作,因此,帧对象可以被分配在堆(Heap)内存中,并且不需要分配连续内存。

  • Native Stack

不是所有的JVM都支持本地方法,然而,基本上都会为每个线程,创建本地方法栈。如果JVM使用C-Linkage模型,实现了JNI(Java Native Invocation),那么本地栈就会是一个C语言的栈。在这种情况下,本地栈中的方法参数和返回值顺序将和C语言程序完全一致。一个本地的方法一般可以回调JVM中的Java方法(依据具体JVM实现而定)。这样的本地方法调用Java方法一般会使用Java栈实现,当前线程将从本地栈中退出,在Java栈中创建一个新的帧。

  • Stack Restrictions

栈可以使一个固定大小或动态大小。如果一个线程请求超过允许的栈空间,允许抛出StackOverflowError。如果一个线程请求创建一个帧,而没有足够内存时,则抛出OutOfMemoryError。

  • Frame

每一个方法被创建的时候都会创建一个 frame,每个 frame 包含以下信息:

  • 本地变量数组 Local Variable Array

  • 返回值

  • 操作对象栈 Operand Stack

  • 当前方法所属类的运行时常量池

  • Local Variables Array

本地变量数组包含所有方法执行过程中的所有变量,包括this引用,方法参数和其他定义的本地变量。对于类方法(静态方法),方法参数从0开始,然后对于实例方法,参数数据的第0个元素是this引用。

本地变量包括:

基本数据类型

bits

bytes

boolean

32

4

byte

32

4

char

32

4

long

64

8

short

32

4

int

32

4

float

32

4

double

64

8

reference

32

4

reference

32

4

所有类型都占用一个数据元素,除了long和double,他们占用两个连续数组元素。(这两个类型是64位的,其他是32位的)

  • Operand Stack

在执行字节代码指令过程中,使用操作对象栈的方式,与在本机CPU中使用通用寄存器相似。大多数JVM的字节码通过压栈、弹栈、复制、交换、操作执行这些方式来改变操作对象栈中的值。因此,在本地变量数组中和操作栈中移动复制数据,是高频操作。

Frame 被创建时,操作栈是空的,操作栈的每个项可以存放JVM 的各种类型,包括 long/double。操作栈有一个栈深,long/double 占用2个栈深,操作栈调用其它有返回结果的方法时,会把结果push 到栈上。

下面举例说明,通过操作对象栈,将一个简单的变量赋值为0.

Java:

int i;

编译后得到以下字节码:

C:

 0:        iconst_0        // 将0压到操作对象栈的栈顶
 1:        istore_1        // 从操作对象栈中弹栈,并将值存储到本地变量1中
  • Dyanmic Linking

每个帧都包含一个引用指针,指向运行时常量池。这个引用指针指向当前被执行方法所属对象的常量池。

当Java Class被编译后,所有的变量和方法引用都利用一个引用标识存储在class的常量池中。一个引用标识是一个逻辑引用,而不是指向物理内存的实际指针。JVM实现可以选择何时替换引用标识,例如:class文件验证阶段、class文件加载后、高频调用发生时、静态编译链接、首次使用时。然后,如果在首次链接解析过程中出错,JVM不得不在后续的调用中,一直上报相同的错误。使用直接引用地址,替换属性字段、方法、类的引用标识被称作绑定(Binding),这个操作只会被执行一次,因为引用标识都被完全替换掉,无法进行二次操作。如果引用标识指向的类没有被加载(resolved),则JVM会优先加载(load)它。每一个直接引用,就是方法和变量的运行时所存储的相对位置,也就是对应的内存偏移量。

  • Share Between Threads

  • Heap

  • Memory Management

  • Non-Heap Memory

  • Just In Time(JIT) compication

  • Method Area

  • Class File structure

  • classloader

  • Faster class Loading

  • Where is the method area

  • Run Time Constant pool

    <
JVM实战(一): dump文件的产生以及执行shell脚本 如何配置jvm参数,在OOM时生成dump文件并执行shell 脚本 阅读详情

相关推荐

在线解析dump 二】 simple-breakpad-server在线解析dump原理及具体操作

1 在线解析dump文件的原理 使用google-breakpad 生成dump文件 用breakpad的 dump_syms.exe 将符号文件(PDB)解析成sym格式的符号文件 用minidump_stackwalk.exe 用来解析dump文件 minidump_stackwalk.exe [options] <minidump-file> [symbol-path ...] Output a stack trace for the provided minidump Optio

大谷的代码日记 3701

JVM内存溢出在线分析Dump文件以及在线分析打开.hprof文件得出JVM运行报告jvisualvm怎么在线分析

我目前在测试环境模拟一些JVM异常的情况,可是不知道怎么进行分析这个,之前公司有测试专家建议使用Jprofile工具可以检测到这个JVM溢出情况,压力测试以及之前有过生产问题,就是使用shiro二级缓存里面配置的ThreadLocal。导致的内存溢出。我这次模拟的是内存不够导致OOM。以及线程过多导致内存溢出!.........

道阻且长,行则将至 行而不辍,未来可期 2577

Java中的JVM指令和Arthas以及Dump文件(jvisualvm和MemoryAnalyzer工具)整体分析

前天线上服务器突然内存和CPU都爆掉了,两者都处于一种高负载的状态,而且还是周末的情况下,起初运维同事怀疑是用户数量暴增,但是数据面板上并没有出现很大的暴增现象,之前的服务器4G的内存都跑不满后面升到8G还是不够,于是我用jps查看了下堆状态,发现老年代的空间占用率99%(大小为5个G),新生代2个多G,于是我怀疑是某个业务一直在创建大量的对象,当然这只能是初步怀疑,接着我又去分析CPU,主要使用了以下命令。

Cover_sky的博客 4049

Java基础】- JVMDump文件详解

Thread Dump是非常有用的诊断Java应用问题的工具。每一个Java虚拟机都有及时生成所有线程在某一个点状态的thread-dump的能力,虽然各个Java虚拟机打印的thread dump稍有不同,但是大部分提供了当前活动线程的快照及JVM中所有Java线程的堆栈跟踪信息,堆栈信息一般包含完整的类名及所执行的方法,如果可能还有源码的行数。如果某种类型的对象太多,那么有可能是引用它的那个类的对象太多;基本上一些简单页面的查询,结合原代码,就可以初步定位内存泄漏的地方;

记录总结工作过往 1万+

JVM Dump分析

Thread Dump介绍 Thread Dump是非常有用的诊断 Java应用问题的工具。每一个 Java虚拟机都有及时生成所有线程在某一点状态的 thread-dump的能力,虽然各个 Java虚拟机打印的 thread dump略有不同,但是大多都提供了当前活动线程的快照,及 JVM中所有 Java线程的堆栈跟踪信息,堆栈信息一般包含完整的类名及所执行的方法,如果可能的话还有源代码的行数。 Thread Dump特点: 【1】能在各种操作系统下使用; 【2】能在各种 Java应用服务器下使用; 【

程序猿进阶 7259

JVM内存Dump原理在线分析实战

当前我们微服务容器化部署JVM 实例很多,常常需要进行JVM heap dump analysis,为了提升JVM 问题排查效率,得技术保障团队研究了JVM内存Dump 原理设计开发JVM 内存在线分析。常见的JVM heap dump analysis 工具如: MAT,JProfile,最常用的功能是大对象分析。功能上本地分析工具更全面,在微服务架构下,成千上万的实例当需要一次分析的时候,于是我们思考如何提供更方便更快的在线分析方便研发人员快速排障。流程传统在线分析相比hprof 获取jmapj

weixin_45536242的博客 4123

java堆栈、gc、dump文件在线分析

HeapHero是一款简单的,易用的内存分析工具,进行dump文件分析。jstack文件在线分析

stay hungry ! stay foolish! 2353

java dump文件分析java虚拟机jvm调优

java dump文件分析什么是dump文件?dump文件的作用如何生成dump文件dump文件分析工具dump文件分析过程 什么是dump文件? Dump文件是进程的内存镜像。可以把程序的执行状态通过调试器保存到dump文件中,可以理解为程序的运行日志。 dump文件的作用 定位宕机故障以及程序性能调优时,咱们在无法得知哪里出现问题的时候就需要查看dump文件去分析当时程序运行的日志,dump中...

main方法 4838

jvm分析篇---1、先认识下dump文件

Dump文件是诊断Java应用内存问题的关键工具,主要包括堆Dump(记录对象内存信息)和线程Dump(捕获线程状态)。

weixin_56693899的博客 895

JVM内存Heap Dump文件GC日志分析

Heap Dump,称为堆转储文件,是Java进程在某个时间内的快照。在触发快照的时候保存了很多信息:Java对象和类信息。通常在写Heap Dump文件前会触发一次Full GC。

积跬步,至千里。 9474

JVM调优的在线网站

1.Alibaba Arthas https://alibaba.github.io/arthas Arthas: 是Alibaba开源的Java诊断工具,深受开发者喜爱,当你遇到:这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗? 以上类似问题而束手无策时,Arthas可以帮助你解决。 2.Aliabba jvmGenerate https://render.alipay.com/p/s/jvm-generate A

青鸟飞鱼 2976

jvm在线分析工具

分享三个实用的在线分析工具: http://www.fastthread.io http://gceasy.io http://heaphero.io

huashetianzu的专栏 9065

在线解析JVM内存溢出 dump文件

在线解析JVM内存溢出 dump文件

weixin_39183923的博客 1323

HeapDump内存在线分析工具

HeapDump - Java内存Dump分析

hongto57的专栏 1640

Arthas排查Java内存溢出

tt -i 1000 -w '{target,params[0]}' # 查看第1000次调用的参数。:查找内存泄漏(Dominator Tree、Leak Suspects)。通过以上步骤,可以快速定位是配置问题、代码缺陷还是资源管理不当导致的OOM。频率是否异常(频繁Full GC可能表明内存不足)。检查是否有线程在大量分配对象(如循环中创建大集合)。:对象因代码逻辑(如静态集合、未关闭资源)无法回收。:仅导出存活对象(减少文件大小)。# 查看方法参数/返回值中的大对象。

qq_45226339的博客 2403

分享一款JVM线程堆栈在线分析工具

小编这些年深知大多数初中级工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。因此我收集整理了一份《2024年Java全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!如果你需要这些资料,⬅专栏获取。

2401_86086721的博客 1225

记录一次Dump文件分析之旅

分析dump文件时,我们建议尝试使用多个工具,以便从不同角度深入分析问题。若存在内存泄漏,可以直接借助JProfiler来识别问题线程和相关对象。如果未发现明显异常,那么可能需要采用其他软件进行进一步分析。事实上,后来发现在IntelliJ IDEA中也能查看完整的对象情况,包括那些等待回收的对象,这为我们的分析提供了更多便利。

庄的博客 1192

JVM :关于捕获 Java Heap Dump 的6种方式

Heap Dump是什么? Heap Dump 也被称为 堆转储文件,是一个Java进程在某个时间点上的内存快照。Heap Dump是有着多种类型的。不过总体上heap dump在触发快照的时候都保存了java对象和类的信息。通常在写heap dump文件前会触发一次FullGC,所以heap dump文件中保存的是FullGC后留下的对象信息。 堆转储文件是诊断内存相关问题的重要信息来源,例如内...

码客 1万+

JVM工作原理实战(三十五):性能调优

JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了性能调优、性能调优案例等内容。

Rye的博客 2115
上一篇: 分布式锁用过没?都用到哪些命令?有没代码完整实例 ?
下一篇: MySQL:不是MySQL问题的MySQL问题
程序员职业指南
博客等级 码龄4年 2108粉丝 960原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值