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

JVM 全面详解:深入理解 Java 的核心运行机制

基础:

Jvm就是java虚拟机,

java执行流程:

文本文件(java)->编译器->.class文件->jvm->虚拟指令->执行引擎->解释为机器指令执行

编译的本质是将java源文件转为jvm能够认识的16进制class文件

类加载机制:

类加载的过程:

将.class文件转化为二进制文件加载到内存中,并转为可以运行的java.lang.Class对象,供jvm使用

1.1装载

  (1)通过类加载器获取类的全限定类名,将class文件转为二进制文件
(2)将二进制流中类的描述信息存入方法区,如:创建时间
(3)将Java.lang.Class对象存入堆中

1.2链接
(1)验证加载类的正确性
(2)在方法区为静态变量分配空间,设置默认0值
(3)把类的符号引用转为直接引用

1.3初始化

为类的静态变量赋值,执行静态代码块

常见类加载器

  • BootstrapClassLoader(启动类加载器):加载核心类库(rt.jarjava.base)。如:java.util.Date,java.lang.String

  • ExtensionClassLoader(扩展类加载器):加载 jre/lib/ext-Djava.ext.dirs 指定目录下的类库。

  • AppClassLoader(应用类加载器):加载 classpath 下的类。

双亲委派模型

类加载收到加载请求时,先由父类加载器去加载,父类加载器无法加载时,再由自己加载

BootstrapClassLoader<-ExtensionClassLoader<-AppClassLoader 依次继承

面试题:如何打破双亲委派机制?

自定义类加载器类,继承ClassLoader类,重写loaderClass方法

内存模型

什么是jvm内存模型 每启动一个java程序,jvm会在进程中划分一块内存区,jvm将内存区划分为5块

jvm内存划分

jvm按照线程是否共享将内存首先分成两大类

线程独享区

只有当前线程能访问数据的区域,线程之间不能共享 线程独享区随线程的创建而创建,随线程的销毁而回收

线程共享区

所有线程都可以访问的区域, 当线程被销毁的时候,共享区的数据不会立即回收,需要等待达到垃圾回收的阈值之后才进行回收

程序计数器

记录当前线程要执行指令的内存地址,为了多线程切换时,能恢复到正确执行位置 只记录一个地址,不会出现内存溢出的问题

虚拟机栈

存当前线程中声明的变量,包括基本数据类型的数据和引用数据类型的引用

基本数据类型:能够确认占用内存的大小

引用数据类型:不能够确认占用内存的大小

将值的引用存放到虚拟机栈中,而对象存放在堆内存中

  栈帧

每一个线程会创建一个虚拟机栈,线程中的每个方法都会在虚拟机栈中创建一个栈帧,存放本次方法执行过程中所需要的所有数据,先进后出

 虚拟机栈溢出及调优

栈溢出99%是因为递归,可以通过修改内存大小设置栈帧的最大深度

本地方法栈(了解,并非四大分区)

存储的是维护非java程序的执行过程中产生的数据

方法区(java8之后叫元空间)

方法区会存储类信息,静态变量,常量,机器指令

如果加载大量class文件,也会造成方法区内存溢出

jvm执行引擎

将字节码指令解释/编译为对应平台上的本地机器指令

解释器:将字节码文件解释为机器指令

即时编译器:会将字节码文件编译为机器指令,存在方法区中,编译完成后直接执行本地机器指令即可

混合模式:

解释器逐条执行字节码,记录热点方法 热点方法交给编译器编译成机器指令

堆内存模型

jvm将对象存放在堆内存,堆内存空间是比较大的。所以我们对于jvm调优,也是主要针对于堆内存调优,比如分配堆内存的空间

对象内存布局

对象头+实例数据+对齐填充()

jvm内存溢出(OOM)和垃圾回收(GC)机制

如果对象只创建不回收,则会造成内存溢出(OOM)

为什么进行堆内存划分?

1.垃圾回收后可以更好的利用内存空间,存放大对象 2.提高搜索垃圾的效率 3.尽可能减少GC次数

堆内存的划分

新生区:占1/3

又分为Eden区和两个Survivor区,且始终有一个Survivor区闲置。对象创建后会先放入Eden区,当Eden区满了之后会进行GC,之后将存活下来的对象复制到闲置的Survivor区,并清空Eden和正在使用的Survivor区。

老年区:占2/3

对象优先分配到新生区内存,每次GC没有回收的对象年龄+1,年龄到15还没有回收,则存放到老年区内存;如果对象较大,超过新生区内存的一半,对象也会放到老年区

YongGC和OldGC

OldGC:之后会进行补齐十分影响性能,尽可能减少

Survivor区空间并不大,满了怎么办?

会触发担保机制,提前将对象存入Old区

为什么需要Survivor区?

为了减少垃圾回收带来的空间碎片,空间碎片过多会频繁触发YongGC

为什么需要两块Survivor区?

为了减少Survivor区的kong

使用VisualVM监听java进程的内存模型

垃圾回收

如何判断垃圾?

引用计数法:

当有一个地方引用它时,计数 +1;引用失效时,计数 -1。

当计数为 0 时,说明对象不再被使用 → 可回收。

会出现循环引用的问题

可达性分析:

从一组 GC Roots 对象出发,沿着对象引用链不断向下搜索。

如果某个对象不能通过任何引用链连接到 GC Roots,就判定为“不可达对象”,就是垃圾。

GC Root对象:

栈帧中引用的对象 方法区中静态属性引用的对象 方法区中常量引用的对象 本地方法栈中引用的对象

回收算法

1.标记-清除

标记所有可达对象,然后清除未标记的,内存碎片化严重

2.复制(新生代)

将内存分为两块,每次只使用一块,当满了时,将存活的对象复制到另一块,清除原有区域

3.标记-整理(老年代)

标记所有可达对象,然后清除未标记的,让存活对象移向一端,减少内存碎片

为什么新生代用复制算法,老年代用标记-整理?

新生代对象存活率低,复制成本小,老年代对象存活率高,复制成本太大,所以用标记-整理

垃圾收集器

CMS收集器

CMS是并发收集器,是基于标记-清除算法进行垃圾回收的,用于OldGC

并发收集,低停顿,但是有内存碎片,停顿时间不可控

G1收集器

并发收集器,能支持YongGC和OldGC

G1没有固定的Old,Yong,Eden,Survivor区,而是将内存分为大小相等的Region,每次回收后,Region的用途可以改变

可以根据开发者设置的参数,停顿时间的期望值,优先回收垃圾最多的Region

CMS 和 G1 有什么区别?” 你可以这样答:

CMS 是一种 低延迟的并发收集器,采用标记-清除算法,适合中小堆内存、对响应时间敏感的应用,但存在内存碎片和浮动垃圾问题。 G1 是 JDK9 默认的收集器,采用 分区化的标记-整理算法,可以避免碎片,并且能根据用户设定的停顿时间优先回收垃圾最多的 Region,更适合大堆内存和对延迟可控要求高的场景。

jvm调优

参数类型

-X参数 -XX参数

1.防止OOM

2.垃圾回收调优

2.1提高吞吐量 2.2减少停顿时间

堆内存文件查看工具

给jvm配置以下代码,让项目发生OOM时自动下载堆内存信息

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heap.hprof

PerfMa查看生成的文件,可以看到各类对象实例数,实例的大小,使用的类加载器

GC日志查看工具

给jvm配置以下代码,将GC信息打印出来到gc.log文件

-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:gc.log

使用GCViewer查看log文件的GC信息,可以看到吞吐量,平均停顿时间,GC次数

jvm监控工具

jvisualVM

能查看参数命令,堆,cpu,类的使用情况

G1GC调优

经过实践,Parallel,CMS,G1,得出G1的吞吐量大,平均停顿时间少,GC次数多

1.适当增加堆内存 2.设置停顿时间 ;设置停顿时间:-XX:MaxGCPauseMillis=

常见面试题补充

内存泄漏和内存溢出是一样的概念吗?

不一样,内存泄漏是指不再使用的对象无法被回收,一直占用内存空间 内存溢出是指程序运行的最大内存大于能提供的最大内存

方法区中的类会被回收吗?

有可能,1.该类的所有实例都被回收,2.该类的类加载器被回收了

CMS 和 G1 的区别

1.cms 只能适用于老年代,g1 可以用于老年代和新生代。

2.cms 使用了标记——清除算法,会产生大量碎片,g1 使用标记——整理算法,减 少了碎片的产生。

3.g1 更加灵活,它将内存分为了一块块 region,并且停顿时间可控。


文章转载自:

http://tvZNoIsU.jhrqn.cn
http://rN6YB6Tj.jhrqn.cn
http://xxMJGoXf.jhrqn.cn
http://3C010EFw.jhrqn.cn
http://RetUvABC.jhrqn.cn
http://SFdlkgIt.jhrqn.cn
http://I2VMKZc2.jhrqn.cn
http://5aTs2Ewu.jhrqn.cn
http://tbDyTrv3.jhrqn.cn
http://T4V2a95D.jhrqn.cn
http://D6qXzRcO.jhrqn.cn
http://FxCaY1ot.jhrqn.cn
http://DTtiCgAC.jhrqn.cn
http://UME8EI2L.jhrqn.cn
http://TiMLRrlj.jhrqn.cn
http://anYogIc5.jhrqn.cn
http://sKrVcYyn.jhrqn.cn
http://GBZ4VtgL.jhrqn.cn
http://fQjd7dYB.jhrqn.cn
http://9n8mvkW9.jhrqn.cn
http://lij2ADqn.jhrqn.cn
http://f2twgR15.jhrqn.cn
http://i6ZYy306.jhrqn.cn
http://RhpvUZkT.jhrqn.cn
http://9TAuF03m.jhrqn.cn
http://QsKqilaJ.jhrqn.cn
http://6iYMwiBa.jhrqn.cn
http://O2JfDs2X.jhrqn.cn
http://FFOuDNUs.jhrqn.cn
http://Gc5BQMpN.jhrqn.cn
http://www.dtcms.com/a/376876.html

相关文章:

  • JVM分代收集:原理与调优策略
  • 使用.NET标准库实现多任务并行处理的详细过程
  • 软件测试:功能测试详解
  • 数字图像处理-图像编码
  • 基于RDMA 通信的可负载均衡高性能服务架构
  • java多线程场景3-并发处理和异步请求
  • <uniapp><指针组件>基于uniapp,编写一个自定义箭头指针组件
  • 新手向:中文语言识别的进化之路
  • Jakarta EE 课程 --- 微型资料投递与分发(Mini Drop-off Box)
  • 【船类】监控录像下船舶类别检测识别数据集:近7k图像,6类,yolo标注
  • 《UE5_C++多人TPS完整教程》学习笔记51 ——《P52 使用我们的瞄准偏移(Using Our Aim Offsets)》
  • 腾讯云远程桌面连接不上?5步排查法解决RDP连接失败
  • ffplay播放pcm
  • 计算机毕业设计 基于Hadoop的B站数据分析可视化系统的设计与实现 Python 大数据毕业设计 Hadoop毕业设计选题【附源码+文档报告+安装调试】
  • 【Halcon 】Halcon 裁剪尺寸的像素陷阱全解析:为什么要 -0.5,为什么要 -1,而圆却不用?
  • 机器视觉质检数据融合PLM:产品缺陷根因分析新范式
  • 【超详细图文教程】2025年最新Win10 系统安装 MySQL 教程
  • 医疗行业面临的网络安全挑战及应对策略
  • JVM CMS垃圾回收器深度解析
  • 鸿蒙Next ArkWeb进程解析:多进程架构如何提升Web体验
  • Credo发布专为低功耗、高带宽与超低时延的AI网络打造的Bluebird 1.6T光DSP芯片
  • Shell 循环语句与函数全解析
  • Zookeeper核心知识全解:节点类型、集群架构与选举机制
  • Android 项目中 Gradle 配置实战:多渠道打包、签名配置、版本管理
  • 新手向:实现验证码程序
  • 【小程序】微信小程序隐私协议
  • LeetCode 刷题【71. 简化路径】
  • 【LeetCode 每日一题】1493. 删掉一个元素以后全为 1 的最长子数组——(解法一)预处理
  • Java代理模式详解
  • 【论文阅读】MEDDINOV3:如何调整视觉基础模型用于医学图像分割?