前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JVM成神之路

JVM成神之路

作者头像
ma布
发布2024-10-22 13:28:20
770
发布2024-10-22 13:28:20
举报
文章被收录于专栏:Java开发

JVM是Java跨平台实现的基础,也是每个Java开发程序员必备的技能之一,因为在后期的JVM调优方面,好的调优结果可以直接影响项目的执行效率,因此本篇文章就会带大家搞懂JVM的常见问题。

首先,当一个基础的问题,JVM是如何运行的,具体的运行流程可以观看我下面画的一张图

基于以上的图片可以得知,JVM执行的流程可以分为下面几步:

1.编译器首先会把 .java 源代码编译为 .class 文件,然年通过类加载器将 .class 文件加载到 运行时数据区域。

2.因为 .class 文件是JVM能识别的一套指令集,操作系统并不认识,因此需要执行引擎来将 .class 文件 进行解释为操作系统可以识别的指令。

3.在执行引擎解释.class文件时,会调用本地方法库的方法来辅助执行。

所以啊,JVM是通过:类加载器,执行引擎,本地方法库,运行时数据区四个模块来执行Java程序的。

明白了JVM是如何运行的,那我们就正式进入JVM的探索之旅啦!!!(搬好小板凳坐好了,准备出发了.....)

JVM入门关:

一:JVM的内存布局是咋样的?

通常所说的内存布局是指运行时数据区,要与Java内存模型分清楚(JMM),运行时数据区是指:堆,虚拟机栈,本地方法栈,方法区,程序计数器五个规范,这是在JVM虚拟机规范所提出来的。

:线程共享的,是JVM中最大的一块区域,存放的是对象的实例

虚拟机栈:线程私有的,存放是方法调用和局部变量(局部变量表,动态链接,操作数栈,方法出口)

本地方法栈:线程私有的,与虚拟机栈类似,存放的是本地方法(c++)

程序计数器:线程私有的,存放的是当前程序进行到了哪一步(当前指令的内存地址)

方法区:线程共享的,存放的是类的结构信息和静态成员变量,常量池等信息。

那什么是Java虚拟机规范呢?

Java虚拟机规范是指各个虚拟机的实现要遵守的一套规则,而Java虚拟机则是规范的具体实现,不同的操作系统都有自己的Java虚拟机实现,因此Java程序在可以一次编写处处可用。

二:方法区,永久代,元空间有什么区别?

方法区是Java虚拟机规范提出的一个专业名词规范,意味着所有的虚拟机实现都会执行该规范,而永久代是Jdk1.7之前的方法区的称呼(默认是使用的HotSpot虚拟机),在1.8之后,用元空间取代了永久代。

为什么要取消永久代呢?

是因为永久代的空间管理很难在满足需求,会出现OOM的问题,因此用元空间取代了永久代,永久代的改动如下:

1.空间大小可以动态调整,这时用的内存空间使用的是本地内存,而不是堆上的内存。

2.字符串常量池从永久代移动到了堆中,减少了方法区GC的压力。

三:常量池和字符串常量池有什么区别?

常量池和字符串常量池都是运行时数据区的一部分,但是二者有以下区别:

1.在jdk1.7之后,将字符串常量池从永久代移动到了堆中,而常量池是存放在元空间中的本地内存中。

2.常量池拥有更多的方法,可以存放字符常量,类,方法,字段的常量,而字符串常量池只可以存放字符串的常量

字符串常量池如下:

四:什么是堆溢出,什么情况下会造成堆溢出

堆溢出是指内存中有大量的垃圾对象无法回收,从而造成堆的内存溢出

常见的堆溢出有以下几种情况:

1.内存泄露:例如使用ThreadLocal时,没有主动释放就会导致内存泄漏。

2.无限创建大量对象

3.没有合理设置堆得大小

4.大量的Execl的导入和导出

五:什么是栈溢出,什么情况下会造成栈溢出

栈溢出通常是指虚拟机栈溢出,而导致虚拟机栈溢出的主要原因是死循环和无限创建大的对象。

例如以下代码,就是一个典型的栈溢出现象,在 main 方法中循环调用 main 方法,循环产生的大量形参都会在栈空间进行创建,当超过栈空间的大小,就会导致栈空间溢出,发生 OOM。

代码语言:javascript
复制
public class StackOverflowErrorDemo {
    public static void main(String[] args) {
        main(args);   // Exception in thread "main" java.lang.StackOverflowError
    }
}

JVM进阶关:

恭喜你,小伙伴已经走到了JVM的进阶关卡了,下面我们就继续向JVM进发吧!!!

六:Java是编译型语言还是解释性语言,什么是JIT,什么是热点代码?

小伙伴是不是刚看到这个还有点懵,这什么东西,还是连着三个???小伙伴不要着急,我们慢慢来分析解决。

首先

解释型语言:不需要事先编译成机器码,而是在程序运行时将源代码逐行解释执行,例如JS语言就是典型的解释型语言 优点:跨平台性能好,无需编译 缺点:执行效率低

编译型语言:在程序执行前将源代码编译成机器可识别的机器码,然后执行,只需要编译一次,生成的可执行文件可重复运行。 优点:执行效率高 缺点:跨平台能力有限

而Java语言是属于二者之间的,也叫编译-解释型语言

编译阶段: .Java源文件经过编译器编译为 .calss 文件(字节码文件与平台无关,可以在任何系统的虚拟机上执行)

解释阶段:当程序执行时,java虚拟机会加载字节码,并对字节码进行解释执行(JIT:即时编译),JIT会对频繁执行的字节码编译成机器指令用来提高性能。

那热点代码又是啥?其实很简单,在不同的Jdk版本中,对于热点代码的定义是有所不同的,在 JDK 21 Client模式下为1500次,而在JDK 21 Server 模式下为10000次

热点代码的识别基于两种策略:方法调用次数和回边计数。

七:对象的生命周期包含哪些?

对象的生命中周期大致可以分为以下几个阶段

1.加载:根据类的全限定名将其转换为此类的二进制字节流,然后将此二进制流加载到运行时数据区中的方法区,在内存中生成一个这个类的对象,作为类的数据访问入口

2.链接

2.1:验证:验证阶段主要是验证此类中的数据是否合法,例如验证文件格式,字节码,符号的引用等

2.2:准备:为类中定义的静态变量分配内存并设置类的初始值,此时并不会真正赋值,而是赋默认值

2.3:解析:将常量池中的符号引用转换为直接引用的过程,也就是初始化常量。

3.初始化:此时Java虚拟机才开始真正执行类的业务代码,将主导权交给主程序

4.使用:在程序中使用该类

5.销毁:此类的实例没有引用时就会根据垃圾回收算法回收此类的实例。

八:什么是双亲委派模型

所谓的双亲委派模型是指:当一个类加载器收到了类加载的请求,首先类不会自己加载而是将请求委派给父类的加载器,每一次都是如此,最终这个类的加载请求会到达顶级类的类加载器即启动类加载器(BootStrap ClassLoader),当父类无法加载该请求时,子类才会尝试自己记载该请求

使用双亲委派模型的好处:

1.避免类的重复记载

2.更加安全

九:Java有哪些场景是打破了双亲委派机制的

1.SPI机制

SPI机制就是“服务提供发现”机制,例如数据库的驱动就是典型SPI机制,用户调用JDBC接口,而各个数据库厂商都会实现JDBC的驱动,因此是从上往下来实现的

2.Tomcat

一个外置的Tomcat要部署多个应用,多个web应用程序在一个Tomcat容器类运行,而不会造成相互干扰和类冲突,因此Tomcat也打破了双亲委派机制

十:Java有哪些引用类型

在jdk1.2以后Java官方提出了四种引用类型,分别为:强引用,软引用,弱引用,虚引用四种

强引用:一般来说,强引用是最常见的,使用Object object = new Object();都是强引用,除非是显示调用System.gc(),一般垃圾回收器不会主动去回收强引用的对象。类似于公司员工的核心员工一样

软引用:软引用是指一些还有用但不是必须回收的对象,类似于公司员工的好员工。只有在内存实在不够用的时候才会去垃圾回收

弱引用:弱引用是指不管内存是否够用,在下一次GC的时候一定会进行垃圾回收的对象,在Java中典型的运用的就是ThreadLocal中value的引用类型就是弱引用,因此为了防止内存泄露,需要爱使用完ThreadLocal后手动调用remove()方法释放内存,类似于公司员工的一般员工一样。

虚引用:在Java中虚引用又称为幻想引用,不能使用虚引用指向的对象,类似于不合格员工。

JVM成神关:

恭喜小伙伴一路过五关斩六将来到了最后的一部分,JVM成神之路.......

十一:如何判断一个对象是否存活

在Java中利用引用计数法和可达性分析算法来判断一个对象是否存活。

引用计数法:给对象增加一个引用计数器,每当有对象引用时计数器+1,当引用失效时计数器-1,当计数器指向0时,表示该对象已经死亡 优点:实现简单,效率高 缺点:无法解决对象之间的循环引用问题

可达性分析:是指通过一个“GC Roots”的根节点开始逐步向下探索,走过的路径称为引用链,当引用链没有与之直接相连的话,就判断该对象是不可存活的。

那么通常又有哪些对象可以成为GC Roots呢?

1.虚拟机栈中引用的对象

2.本地方法栈中引用的对象

3.方法区中静态变量的引用对象

4.方法区中常量的引用对象

十二:常见的垃圾回收算法有哪些?

在Java中常见的垃圾回收算法有:标记-清除算法,标记-整理算法,复制算法,分代算法等

标记-清除算法:是Java垃圾回收算法中最常见的一种垃圾回收算法,它的核心思想是统一标记可回收的对象,然后统一进行垃圾回收 优点:执行效率比较高,实现简单 缺点:使用标记-清除算法会出现大量的垃圾碎片,如果需要一大片连续的内存空间时候,此种垃圾回收的效率就会打折扣。

标记-整理算法:标记-整理算法其实是标记-清除算法的一种升级,在统一标记后并不会立即执行垃圾回收,而是将存活的对象移动到另一端,然后清理端外的垃圾对象。 优点:不会存在垃圾碎片的问题 缺点:执行效率比较低下,因为在标记后还需要进行整理存活对象到另一端

复制算法:复制算法是标记-整理算法的一种升级,它的目的就是解决标记-整理算法的效率问题,它将可用内存区域按容量划分为两块大小相等的区域,然后在一块区域进行使用,当需要垃圾回收的时候,会将使用区域的存活对象复制到另一块未使用的区域,然后统一清除使用区域的垃圾对象 优点:执行效率高,不会存在垃圾碎片 缺点:内存空间的利用率比较低

分代算法:分代算法就是将堆内存区域划分为新生代,老生代,然后在各自的区域进行垃圾回收的一种算法

分代算法的大致流程如下:

将堆内存区域划分为新生代,老生代,新生代占比1/3,老生代占比2/3,然后新生代区域又细分为3个区域:end区,To Survivor ,From Survivor占比分别为8:1:1 执行流程大致如下: 1.end区+from Survivor区存活的对象放入 To Survivor区

2.清空end区,from Survivor区

3.交换from Survivor区,To Survivor区

每交换一次存活的对象的年龄+1,当对象的年龄到达15时(HostPot默认是15),就会将该对象放进老生代,当老生代的区域不够用时,就会触发Full GC(全局垃圾回收)。

十三:JVM常见的垃圾回收器有哪些?

常见的垃圾回收器下图所示:在新生代的Serial,ParNew,parallel Scavenge 在老生代的Serial Old,CMS,Parallel Old 已经后续一直在沿用的默认的垃圾回收器G1

在新生代的垃圾回收器常采用的垃圾回收算法是复制算法,在老生代采用的则是标记-整理算法

Serial,Serial Old是单线程环境下的串行执行的,不支持并发操作,意味着在进行垃圾回收时会阻塞用户线程,直到垃圾收集完成。

ParNew 相当于Serial的升级版本,唯一的区别就是ParNew 采用的并行回收,适用于多线程环境下

Parallel Scavenge,Parallel Old是专注于吞吐量的垃圾回收器 (吞吐量 = 用户线程执行时间/总时间 * 100% = 用户线程执行时间/(GC时间+用户线程执行时间)* 100%)

CMS:专注于最短停顿时间的垃圾回收器

十四:CMS垃圾回收器有什么特点

CMS:并发标记清理回收器,是一种获取最短回收停顿时间为目标的垃圾收集器

CMS第一次初始标记,实现用户线程和垃圾回收线程同时执行 ,采用的是标记-清除垃圾回收算法,也会存在STW(Stop the word,全局停顿),是一款老生代的垃圾回收器

优点:低延迟,并发收集 缺点:采用标记-清除算法会产生垃圾碎片

十五:CMS垃圾回收期的执行流程是怎么样的呢?

CMS的执行流程如图所示

1.初始标记:只标记GC Roots直接关联的对象,速度很快

2.并发标记:和用户线程同时会执行:GC Roots直接关联的对象继续向下探索,形成一条引用链

3.重新标记:对上一步“并发标记”阶段用户线程还在执行对象的变动进行修正标记

4.并发清除:使用并发-清除算法进行垃圾回收

好了,恭喜小伙伴,已经成功完成了JVM成神之路的所有关卡,与预祝小伙伴在未来的编程生涯中一路畅通,永无BUG!!!

(PS:本文一些图片配图来自于其他网络,若图片作者有看到请联系我删除)

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-10-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • JVM入门关:
    • 一:JVM的内存布局是咋样的?
      • 二:方法区,永久代,元空间有什么区别?
        • 三:常量池和字符串常量池有什么区别?
          • 四:什么是堆溢出,什么情况下会造成堆溢出
            • 五:什么是栈溢出,什么情况下会造成栈溢出
            • JVM进阶关:
              • 六:Java是编译型语言还是解释性语言,什么是JIT,什么是热点代码?
                • 七:对象的生命周期包含哪些?
                  • 八:什么是双亲委派模型
                    • 九:Java有哪些场景是打破了双亲委派机制的
                      • 1.SPI机制
                      • 2.Tomcat
                    • 十:Java有哪些引用类型
                    • JVM成神关:
                      • 十一:如何判断一个对象是否存活
                        • 十二:常见的垃圾回收算法有哪些?
                          • 十三:JVM常见的垃圾回收器有哪些?
                            • 十四:CMS垃圾回收器有什么特点
                              • 十五:CMS垃圾回收期的执行流程是怎么样的呢?
                              相关产品与服务
                              容器服务
                              腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                              领券
                              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档