百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 优雅编程 > 正文

Java 虚拟机经典六问(java虚拟机运行java程序的基本步骤)

sinye56 2024-09-23 23:47 5 浏览 0 评论

大家好,我是郑雨迪。很荣幸,我开设的《深入拆解 Java 虚拟机》专栏得到了大家的青睐,有了 20000+ 的订阅。很显然,现在越来越多的程序员意识到了 Java 虚拟机的重要性,渴望去了解底层,迫切想通过系统性的学习深入 Java 虚拟机,达到“知其然且知其所以然”的目的。

在专栏开更到完结期间,我收到了不下几千条问题,尽量都做了解答。现特意整理出了 6 个高频问题,分享给大家,算做一篇加餐文。希望大家能继续深耕 JVM,提升日常编程的效率,实现技术进阶,挖掘到更多的宝藏。

1、Java 是如何在保证可移植性的前提下提供高执行效率的?


Java 程序最为常见的执行方式,是预先编译为一种名为 Java 字节码的中间代码格式。这种代码格式无法直接运行在 CPU 之上,而是需要借助 JVM 来执行。换句话说,只要某个平台提供了合乎 JVM 规范的实现,它便能执行这份 Java 字节码。这也就是我们经常说的“一次编写,到处运行”。

主流的 OpenJDK/OracleJDK 中所提供的 JVM 叫做 HotSpot。它同时采用了解释执行和即时编译。解释执行就好比同声传译,JVM 一边理解输入的字节码一边向 CPU 发出指令序列;即时编译则是“磨刀不误砍柴工”,JVM 会在运行过程中将热点代码编译成为可直接执行的二进制代码。

这种混合执行模式是建立在程序符合二八定律的假设上,即百分之二十的代码占据了百分之八十的计算资源。对于不常用代码,我们无需耗费时间将其编译成二进制代码,而是采取解释执行的方式运行;另一方面,对于仅占据小部分的热点代码,JVM 则会花费时间将其编译为二进制代码,以达到理想的运行效率。

2、异常捕获是如何实现的?


在编译生成的 Java 字节码中,每个方法都附带一个异常表。异常表中的每一行均定义了一条异常执行路径,其中包括规定捕获范围的起始字节码索引、终止(不包含)字节码索引,异常处理代码的起始字节码索引,以及所捕获的异常类型。

当程序触发异常时,JVM 会从上至下遍历异常表中的所有条目。当触发异常的字节码的索引值在某行异常表条目的捕获范围内,JVM 会判断所抛出的异常和该条目想要捕获的异常是否匹配。如果匹配,JVM 会将控制流转移至该条目所指向的异常处理代码。

上述异常捕获机制还被用于 finally 从句的实现。通常,Java 程序的编译器 javac 会复制多份 finally 代码块,放置于生成的 Java 字节码之中,然后通过生成多行异常表条目,来实现完整的 finally 逻辑。

3、反射调用为什么慢?


默认情况下,反射调用首先会被委派给 native 方法来进行。可想而知,其运行效率低下。当某个反射调用的调用次数达到 15 之后,JDK 代码断定该调用属于热点调用。继而,JDK 将动态生成直接调用目标方法的字节码,并将反射调用的委派对象由原本的 native 方法实现切换至该动态生成的实现。这种方式的运行效率相对于 native 方法来说要高很多。

之所以 JDK 不从一开始便采用动态生成字节码的方式,主要是因为生成过程需要耗费一定的时间。对于那些整个生命周期中仅执行数次的反射调用,动态生成字节码将得不偿失。

然而,即便是直接调用目标方法的动态实现,其峰值性能也无法跟真正的直接调用相媲美。这背后涉及到即时编译中的虚方法内联。

4、垃圾回收的基础思想是什么?


目前 JVM 的主流垃圾回收器采取的都是可达性分析算法。该算法的实质是将一系列被称为 GC Roots 的对象作为初始的存活对象合集,然后从该合集出发探索所有能够被该集合引用到的对象,并标记为存活对象。当标记阶段结束之后,未被标记到的对象便是可以清除的。

传统的垃圾回收算法在标记、清除过程中需要中止其他应用线程,即所谓的 Stop-The-World。新型的垃圾回收算法,如 CMS、G1 以及 ZGC,尽可能地实现并发标记、清除,从而让 Stop-The-World 的时间长度可控。

垃圾回收的另一基础思想则是分代回收。JVM 会将新生成的对象划为新生代,而将在多次垃圾回收中存活下来的对象划为老年代。JVM 会为不同的分代设置不同的回收算法,从而达到新生代多收集、快收集,老年代少收集、全收集的目标。

5、如何理解 Java 内存模型?

现代计算机多为对称多处理器的体系架构。每个处理器均有独立的寄存器组和缓存(这在 Java 内存模型中被抽象为工作内存);多个处理器可同时执行同一进程中的不同线程。

在 Java 程序中,不同线程可能访问同一变量或对象。如果任由编译器或处理器对这些访问进行优化,则很可能出现在单线程执行思维下无法想象的问题。因此,Java 语言规范引入了 Java 内存模型,通过定义多项规则对编译器和处理器进行限制。

这些规则所体现的最为重要的属性便是可见性,即对某一变量的访问能否被同一线程的其他操作,或者不同线程所观测到。Java 内存模型引入了多种 happens-before 关系,以实现上述可见性。以 volatile 字段为例,对其的写操作 happens before 这之后的读操作,也就是说,我们总能读到 volatile 字段的最新值。

6、JVM 如何应对对象锁的各种场景?

重量级锁是最为基础、最为低效的对象锁实现。JVM 会阻塞加锁失败的线程,并且在目标锁被释放的时候,唤醒这些线程。我们用等红灯作类比。Java 线程进入阻塞状态相当于熄火停车,再次点火启动必然耗费时间。JVM 会在进入阻塞状态之前进行自旋,也就是怠速停车。如果目标锁能够在短时间内被释放出来,该线程便能够不进入阻塞状态,直接获取该锁。

重量级锁针对的是多个线程同时竞争同一把锁的场景。在现实中,多个线程可能在不同时间段持有同一把锁。为了应对这种没有锁竞争的情况,JVM 采用了轻量级锁机制。在加锁时,JVM 将在锁对象处做标记,指向当前线程的栈上;在解锁时,上述标记会被清除。如果某线程在请求锁时,发现该锁为轻量级锁,并且指向另一线程所对应的栈,那么它会将该锁膨胀为重量级锁。

偏向锁所应对的场景则更为乐观:至始至终只有一个线程请求某把锁。JVM 采取的做法是在第一次加锁时为锁对象做标记,使其指向当前线程的地址;在解锁时则不做任何操作。如果下一次请求该锁的仍是同一线程,便直接跳过标记过程;否则,JVM 会将该锁膨胀为轻量级锁。

文章出自极客时间《深入拆解 Java 虚拟机》专栏。

相关推荐

程序员:JDK的安装与配置(完整版)_jdk的安装方法

对于Java程序员来说,jdk是必不陌生的一个词。但怎么安装配置jdk,对新手来说确实头疼的一件事情。我这里以jdk10为例,详细的说明讲解了jdk的安装和配置,如果有不明白的小伙伴可以评论区留言哦下...

Linux中安装jdk并配置环境变量_linux jdk安装教程及环境变量配置

一、通过连接工具登录到Linux(我这里使用的Centos7.6版本)服务器连接工具有很多我就不一一介绍了今天使用比较常用的XShell工具登录成功如下:二、上传jdk安装包到Linux服务器jdk...

麒麟系统安装JAVA JDK教程_麒麟系统配置jdk

检查检查系统是否自带java在麒麟系统桌面空白处,右键“在终端打开”,打开shell对话框输入:java–version查看是否自带java及版本如图所示,系统自带OpenJDK,要先卸载自带JDK...

学习笔记-Linux JDK - 安装&配置

前提条件#检查是否存在JDKrpm-qa|grepjava#删除现存JDKyum-yremovejava*安装OracleJDK不分系统#进入安装文件目...

Linux新手入门系列:Linux下jdk安装配置

本系列文章是把作者刚接触和学习Linux时候的实操记录分享出来,内容主要包括Linux入门的一些理论概念知识、Web程序、mysql数据库的简单安装部署,希望能够帮到一些初学者,少走一些弯路。注意:L...

测试员必备:Linux下安装JDK 1.8你必须知道的那些事

1.简介在Oracle收购Sun后,Java的一系列产品就被整合到Oracle官网中,打开官网乍眼一看也不知道去哪里下载,还得一个一个的摸索尝试,而且网上大多数都是一些Oracle收购Sun前,或者就...

Linux 下安装JDK17_linux 安装jdk1.8 yum

一、安装环境操作系统:JDK版本:17二、安装步骤第一步:下载安装包下载Linux环境下的jdk1.8,请去官网(https://www.oracle.com/java/technologies/do...

在Ubuntu系统中安装JDK 17并配置环境变量教程

在Ubuntu系统上安装JDK17并配置环境变量是Java开发环境搭建的重要步骤。JDK17是Oracle提供的长期支持版本,广泛用于开发Java应用程序。以下是详细的步骤,帮助你在Ubuntu系...

如何在 Linux 上安装 Java_linux安装java的步骤

在桌面上拥抱Java应用程序,然后在所有桌面上运行它们。--SethKenlon(作者)无论你运行的是哪种操作系统,通常都有几种安装应用程序的方法。有时你可能会在应用程序商店中找到一个应用程序...

Windows和Linux环境下的JDK安装教程

JavaDevelopmentKit(简称JDK),是Java开发的核心工具包,提供了Java应用程序的编译、运行和开发所需的各类工具和类库。它包括了JRE(JavaRuntimeEnviro...

linux安装jdk_linux安装jdk软连接

JDK是啥就不用多介绍了哈,外行的人也不会进来看我的博文。依然记得读大学那会,第一次实验课就是在机房安装jdk,编写HelloWorld程序。时光飞逝啊,一下过了十多年了,挣了不少钱,买了跑车,娶了富...

linux安装jdk,全局配置,不同用户不同jdk

jdk1.8安装包链接:https://pan.baidu.com/s/14qBrh6ZpLK04QS8ogCepwg提取码:09zs上传文件解压tar-zxvfjdk-8u152-linux-...

运维大神教你在linux下安装jdk8_linux安装jdk1.7

1.到官网下载适合自己机器的版本。楼主下载的是jdk-8u66-linux-i586.tar.gzhttp://www.oracle.com/technetwork/java/javase/downl...

window和linux安装JDK1.8_linux 安装jdk1.8.tar

Windows安装JDK1.8的步骤:步骤1:下载JDK打开浏览器,找到JDK下载页面https://d.injdk.cn/download/oraclejdk/8在页面中找到并点击“下载...

最全的linux下安装JavaJDK的教程(图文详解)不会安装你来打我?

默认已经有了linux服务器,且有root账号首先检查一下是否已经安装过java的jdk任意位置输入命令:whichjava像我这个已经安装过了,就会提示在哪个位置,你的肯定是找不到。一般我们在...

取消回复欢迎 发表评论: