硬核干货——《中小企业 AI 实战指南》免费下载! 了解详情
写点什么

Java 虚拟机经典六问

  • 2019-01-18
  • 本文字数:2440 字

    阅读完需:约 8 分钟

Java 虚拟机经典六问

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


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

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


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


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


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

异常捕获是如何实现的?


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


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


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

反射调用为什么慢?


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


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


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


相关文章:< 方法内联(下)>

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


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


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


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

如何理解 Java 内存模型?

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


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


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

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

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


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


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


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


2019-01-18 16:249217

评论

发布
暂无评论
发现更多内容

CAD怎么根据浮动范围选择圆

极客天地

【IoTDB 线上小课 14】我们为什么要做树表双模型?

Apache IoTDB

出版社题库管理系统的测试

北京木奇移动技术有限公司

软件外包公司 出版社 题库系统开发

本周六,龙蜥社区邀您共赴第三届 eBPF 开发者大会

OpenAnolis小助手

操作系统 龙蜥社区 eBPF开发者大会

小白速进!30 天吃透低代码,全是超绝干货!

代码制造者

低代码 自学 无代码

Sentinel源码—ProcessorSlot的执行过程

电子尖叫食人鱼

人工智能与网络安全:AI如何预防、检测和应对网络攻击?

天津汇柏科技有限公司

人工智能 网络安全 AI 人工智能

通义灵码 Rules 库合集来了,覆盖Java、TypeScript、Python、Go、JavaScript 等

阿里云云效

阿里云 云原生 通义灵码

Java 开发玩转 MCP:从 Claude 自动化到 Spring AI Alibaba 生态整合

阿里巴巴云原生

Java

深度探讨操作系统运维、软件选型等社区标准,龙蜥标准化 SIG MeetUp 圆满举办

OpenAnolis小助手

操作系统 龙蜥社区 龙蜥sig 标准化 SIG 龙蜥meetup

龙蜥邀您参加 2025 全国大学生计算机系统能力大赛操作系统设计赛

OpenAnolis小助手

操作系统 开源大赛

CAD如何放大图纸

极客天地

超实用!用FunctionCall实现快递AI助手

王磊

行业热点丨为什么AI驱动工程对汽车设计和轻量化至关重要?

Altair RapidMiner

人工智能 AI 汽车 数字孪生 CAE

深入研究:微店商品详情API接口详解

tbapi

微店商品详情接口 微店API 微店数据采集

虚拟化NFSoRDMA基础的分离式存储解决方案,用于AI工作负载

Sergey Platonov

性能测试 虚拟化 高性能计算, 高性能计算架构

让我看看有多少人不知道Vue3中也能实现高阶组件HOC

不在线第一只蜗牛

Java JavaScript 前端

[方法讨论]手机号码批量导入手机通讯录,导入苹果iphone通讯录华为手机小米手机等安卓手机

一码平川

重大升级| SecGPT V2.0:打造真正“懂安全”的大模型

云起无垠

Anolis OS 8.10 发布:软硬协同优化,满足多行业实际应用需求

OpenAnolis小助手

操作系统 龙蜥社区 龙蜥操作系统 Anolis OS

CAD怎么将实体转换为网格

极客天地

真正懂生产的工业智能体长啥样?一个评测告诉你答案

王吉伟频道

工业互联网 智能体 工业智能体 Agents 工业大模型

AI阅读眼动就翻页,领权益解锁HUAWEI Pura X内容新体验

最新动态

基于TiDB的应用多活架构

陈一之

TiDB 多活容灾 应用多活

数字先锋|文化传承新引擎:班智达科研项目云端腾飞!

天翼云开发者社区

云服务 教育数字化

通义灵码 Rules 库合集来了,覆盖Java、TypeScript、Python、Go、JavaScript 等

阿里巴巴云原生

阿里云 云原生 通义灵码

云备份技术解析:云备份 CT-CBR 关键技术介绍

天翼云开发者社区

云备份

广告营销行业使用堡垒机的场景简单聊聊

行云管家

网络安全 信息安全

2025 全球分布式云大会演讲实录 | 沈建发:智启边缘,畅想未来:边缘计算新场景落地与 Al 趋势新畅想

火山引擎边缘云

人工智能 边缘计算 AI 大底座 边缘智能

技术干货推荐:高效解决性能瓶颈与抖动之进程热点追踪

OpenAnolis小助手

操作系统 SysOM 操作系统控制台

云智赋能,绘就农业强国新图景!

天翼云开发者社区

智慧农业 数字孪生 农业数字化

Java 虚拟机经典六问_Java_郑雨迪_InfoQ精选文章