深入理解Java虚拟机
文章平均质量分 94
深入理解Java虚拟机:JVM高级特性与最佳实践
一直不懂
笔记
展开
-
字节码指令简介
Java虚拟机的指令由一个字节长度的、代表着某种特定操作含义的数字(称为操作码,Opcode) 以及跟随其后的零至多个代表此操作所需的参数(称为操作数,Operand)构成。由于Java虚拟机采用 面向操作数栈而不是面向寄存器的架构(这两种架构的执行过程、区别和影响将在第8章中探讨),所 以大多数指令都不包含操作数,只有一个操作码,指令参数都存放在操作数栈中。字节码指令集可算是一种具有鲜明特点、优势和劣势均很突出的指令集架构,由于限制了Java虚 拟机操作码的长度为一个字节(即0~255),这意味着指令集转载 2020-12-27 15:32:26 · 1413 阅读 · 0 评论 -
附录D 对象查询语言(OQL)简介
1 SELECT子句SELECT子句用于确定查询语句需要从堆转储快照中选择什么内容。如果需要显示堆转储快照中的对象,并且浏览这些对象的引用关系,可以使用“*”,这与传统SQL语句中的习惯是一致的,如:SELECT * FROM java.lang.String 1.选择特定的显示列查询也可以选择特定的需要显示的字段,如:SELECT toString(s), s.count, s.value FROM java.lang.String s 查询可以通过“@”符号来使用Java对象的内存属性访转载 2021-01-03 17:06:17 · 1285 阅读 · 0 评论 -
线程安全与锁优化
1 概述在软件业发展的初期,程序编写都是以算法为核心的,程序员会把数据和过程分别作为独立的部分来考虑,数据代表问题空间中的客体,程序代码则用于处理这些数据,这种思维方式直接站在计算机的角度去抽象问题和解决问题,被称为面向过程的编程思想。与此相对,面向对象的编程思想则站在现实世界的角度去抽象和解决问题,它把数据和行为都看作对象的一部分,这样可以让程序员能以符合现实世界的思维方式来编写和组织程序。面向对象的编程思想极大地提升了现代软件开发的效率和软件可以达到的规模,但是现实世界与计算机世界之间不可避免地存在转载 2021-01-03 14:31:06 · 272 阅读 · 0 评论 -
Java内存模型与线程
1 概述多任务处理在现代计算机操作系统中几乎已是一项必备的功能了。在许多场景下,让计算机同时去做几件事情,不仅是因为计算机的运算能力强大了,还有一个很重要的原因是计算机的运算速度与它的存储和通信子系统的速度差距太大,大量的时间都花费在磁盘I/O、网络通信或者数据库访问上。如果不希望处理器在大部分时间里都处于等待其他资源的空闲状态,就必须使用一些手段去把处理器的运算能力“压榨”出来,否则就会造成很大的性能浪费,而让计算机同时处理几项任务则是最容易想到,也被证明是非常有效的“压榨”手段。除了充分利用计算机处转载 2021-01-02 22:38:02 · 229 阅读 · 0 评论 -
后端编译与优化
1 概述如果我们把字节码看作是程序语言的一种中间表示形式(Intermediate Representation,IR)的话,那编译器无论在何时、在何种状态下把Class文件转换成与本地基础设施(硬件指令集、操作系统)相关的二进制机器码,它都可以视为整个编译过程的后端。如果读者阅读过本书的第2版,可能会发现本章的标题已经从“运行期编译与优化”悄然改成了“后端编译与优化”,这是因为在2012年的Java世界里,虽然提前编译(Ahead Of Time,AOT)早已有所应用,但相对而言,即时编译(Just I转载 2021-01-01 18:52:22 · 1277 阅读 · 0 评论 -
前端编译与优化
1 概述在Java技术下谈“编译期”而没有具体上下文语境的话,其实是一句很含糊的表述,因为它可能是 指一个前端编译器(叫“编译器的前端”更准确一些)把*.java文件转变成*.class文件的过程;也可能是 指Java虚拟机的即时编译器(常称JIT编译器,Just In Time Compiler)运行期把字节码转变成本地机器 码的过程;还可能是指使用静态的提前编译器(常称AOT编译器,Ahead Of Time Compiler)直接把程 序编译成与目标机器指令集相关的二进制代码的过程。下面笔者列举了这转载 2021-01-01 14:43:46 · 838 阅读 · 0 评论 -
类加载及执行子系统的案例与实战
1 概述在Class文件格式与执行引擎这部分里,用户的程序能直接参与的内容并不太多,Class文件以何种格式存储,类型何时加载、如何连接,以及虚拟机如何执行字节码指令等都是由虚拟机直接控制的行为,用户程序无法对其进行改变。能通过程序进行操作的,主要是字节码生成与类加载器这两部分的功能,但仅仅在如何处理这两点上,就已经出现了许多值得欣赏和借鉴的思路,这些思路后来成为许多常用功能和程序实现的基础。在本章中,我们将看一下前面所学的知识在实际开发之中是如何应用的。2 案例分析在案例分析部分,笔者准备了4个例子转载 2020-12-31 17:54:33 · 212 阅读 · 0 评论 -
虚拟机字节码执行引擎
1 概述执行引擎是Java虚拟机核心的组成部分之一。“虚拟机”是一个相对于“物理机”的概念,这两种机器都有代码执行能力,其区别是物理机的执行引擎是直接建立在处理器、缓存、指令集和操作系统层面上的,而虚拟机的执行引擎则是由软件自行实现的,因此可以不受物理条件制约地定制指令集与执行引擎的结构体系,能够执行那些不被硬件直接支持的指令集格式。在《Java虚拟机规范》中制定了Java虚拟机字节码执行引擎的概念模型,这个概念模型成为各大发行商的Java虚拟机执行引擎的统一外观(Facade)。在不同的虚拟机实现中,转载 2020-12-29 00:20:52 · 304 阅读 · 0 评论 -
Java模块化系统
在JDK 9中引入的Java模块化系统(Java Platform Module System,JPMS)是对Java技术的一次重要升级,为了能够实现模块化的关键目标——可配置的封装隔离机制,Java虚拟机对类加载架构也做出了相应的变动调整,才使模块化系统得以顺利地运作。JDK 9的模块不仅仅像之前的JAR包那样只是简单地充当代码的容器,除了代码外,Java的模块定义还包含以下内容:依赖其他模块的列表。导出的包列表,即其他模块可以使用的列表。开放的包列表,即其他模块可反射访问模块的列表。使用的服务转载 2020-12-28 01:02:19 · 859 阅读 · 0 评论 -
JVM类加载器
虚拟机设计团队把类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类。实现这个动作的代码模块称为“类加载器”。1、类与类加载器类加载器虽然只用于实现类的加载动作,但它在Java程序中起到的作用却远远不限于类加载阶段。对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在Java虚拟机中的...转载 2019-07-21 13:50:23 · 142 阅读 · 0 评论 -
JVM类加载机制
1、概述虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。与那些在编译时需要进行连接工作的语言不同,在Java语言里面,类型的加载、连接和初始化过程都是在程序运行期间完成的,这种策略虽然会令类加载时稍微增加一些性能开销,但是会为Java应用程序提供高度的灵活性,Java里天生可以动态扩展...转载 2019-07-21 12:25:52 · 188 阅读 · 0 评论 -
Class类文件的结构
任何一个Class文件都对应着唯一的一个类或接口的定义信息[1],但是反过来说,类或接口并不一定都得定义在文件里(譬如类或接口也可以动态生成,直接送入类加载器中)。本章中,笔者只是通俗地将任意一个有效的类或接口所应当满足的格式称为“Class文件格式”,实际上它完全不需要以磁盘文件的形式存在。Class文件是一组以8个字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑地排列在文件之中,中间没有添加任何分隔符,这使得整个Class文件中存储的内容几乎全部是程序运行的必要数据,没有空隙存在。当遇到需要占用转载 2020-12-26 17:25:50 · 589 阅读 · 2 评论 -
实战:Eclipse运行速度调优
很多Java开发人员都有一种错觉,认为系统调优的工作都是针对服务端应用的,规模越大的系统,就需要越专业的调优运维团队参与。这个观点不能说不对,只是有点狭隘了。上一节中笔者所列举的案例确实大多是服务端运维、调优的例子,但不只服务端需要调优,其他应用类型也是需要的,作为一个普通的Java开发人员,学习到的各种虚拟机的原理和最佳实践方法距离我们并不遥远,开发者身边就有很多场景可以使用上这些知识。下面就通过一个普通程序员日常工作中可以随时接触到的开发工具开始这次实战[1]。1、调优前的程序运行状态笔者使用Ecl转载 2020-12-25 17:38:42 · 1835 阅读 · 1 评论 -
JVM调优案例分析
1、大内存硬件上的程序部署策略这是笔者很久之前处理过的一个案例,但今天仍然具有代表性。一个15万PV/日左右的在线文档类型网站最近更换了硬件系统,服务器的硬件为四路志强处理器、16GB物理内存,操作系统为64位 CentOS 5.4,Resin作为Web服务器。整个服务器暂时没有部署别的应用,所有硬件资源都可以提供给这访问量并不算太大的文档网站使用。软件版本选用的是64位的JDK 5,管理员启用了一个虚拟机实例,使用-Xmx和-Xms参数将Java堆大小固定在12GB。使用一段时间后发现服务器的运行效果十转载 2020-12-25 16:26:50 · 1650 阅读 · 2 评论 -
HotSpot虚拟机插件及工具
HotSpot虚拟机发展了二十余年,现在已经是一套很复杂的软件系统,如果深入挖掘HotSpot的源码,可以发现在HotSpot的研发过程中,开发团队曾经编写(或者收集)过不少虚拟机的插件和辅助工 具,它们存放在HotSpot源码hotspot/src/share/tools目录下,包括(含曾经有过但新版本中已被移除 的):Ideal Graph Visualizer:用于可视化展示C2即时编译器是如何将字节码转化为理想图,然后转化为机器码的。Client Compiler Visualizer[1]:转载 2020-12-25 14:50:08 · 644 阅读 · 0 评论 -
JDK可视化故障处理工具
JDK中除了附带大量的命令行工具外,还提供了几个功能集成度更高的可视化工具,用户可以使 用这些可视化工具以更加便捷的方式进行进程故障诊断和调试工作。这类工具主要包括JConsole、 JHSDB、VisualVM和JMC四个。其中,JConsole是最古老,早在JDK 5时期就已经存在的虚拟机监控 工具,而JHSDB虽然名义上是JDK 9中才正式提供,但之前已经以sa-jdi.jar包里面的HSDB(可视化工具)和CLHSDB(命令行工具)的形式存在了很长一段时间[1]。它们两个都是JDK的正式成员,随着转载 2020-12-25 01:53:40 · 704 阅读 · 0 评论 -
JDK基础故障处理工具
JDK的bin目录中有各种小工具,这些故障处理工具并不单纯是被Oracle公司作为“礼物”附赠给JDK的使用者,根据软件可用性和授 权的不同,可以把它们划分成三类:商业授权工具:主要是JMC(Java Mission Control)及它要使用到的JFR(Java Flight Recorder),JMC这个原本来自于JRockit的运维监控套件从JDK 7 Update 40开始就被集成到OracleJDK 中,JDK 11之前都无须独立下载,但是在商业环境中使用它则是要付费的[1]。正式支持工具:转载 2020-11-29 17:55:49 · 6607 阅读 · 0 评论 -
JVM内存分配与回收策略
对象的内存分配,往大的方向上讲,就是在堆上分配,少数情况下也可能会直接分配在老年代中,分配的规则并不是百分之百固定的,其细节决定于当前使用的是哪种垃圾收集器组合,当然还有虚拟机中与内存相关的参数。垃圾收集器组合一般就是Serial+Serial Old和Parallel+Serial Old,前者是Client模式下的默认垃圾收集器组合,后者是Server模式下的默认垃圾收集器组合,文章使用对比学...转载 2019-07-19 10:57:47 · 147 阅读 · 0 评论 -
选择合适的垃圾收集器
HotSpot虚拟机提供了种类繁多的垃圾收集器,选择太多反而令人踌躇难决,若只挑最先进的显然不可能满足全部应用场景,但只用一句“必须因地制宜,按需选用”又未免有敷衍的嫌疑,本节我们就来探讨一下如何选择合适的垃圾收集器。Epsilon收集器在G1、Shenandoah或者ZGC这些越来越复杂、越来越先进的垃圾收集器相继出现的同时,也有一 个“反其道而行”的新垃圾收集器出现在JDK 11的特征清单中——Epsilon,这是一款以不能够进行垃圾 收集为“卖点”的垃圾收集器,这种话听起来第一感觉就十分违反逻辑,转载 2020-11-22 16:39:48 · 496 阅读 · 0 评论 -
低延迟垃圾收集器
HotSpot的垃圾收集器从Serial发展到CMS再到G1,经历了逾二十年时间,经过了数百上千万台服务器上的应用实践,已经被淬炼得相当成熟了,不过它们距离“完美”还是很遥远。怎样的收集器才算是“完美”呢?这听起来像是一道主观题,其实不然,完美难以实现,但是我们确实可以把它客观描述出来。衡量垃圾收集器的三项最重要的指标是:内存占用(Footprint)、吞吐量(Throughput)和延迟(Latency),三者共同构成了一个“不可能三角[1]”。三者总体的表现会随技术进步而越来越好,但是要在这三个方面同转载 2020-11-18 23:36:35 · 507 阅读 · 0 评论 -
HotSpot VM的收集器
如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。虚拟机具体如何进行内存回收动作,是由虚拟机所采用的GC收集器所决定的,而通常虚拟机中往往不止有一种GC收集器,像目前(JDK 7时代)的HotSpot里面就包含有Serial、Serial Old、ParNew、Parallel Scavenge(简称PS)、Parallel Old、Concurrent Mark Sweep...转载 2019-07-18 17:34:38 · 175 阅读 · 0 评论 -
HotSpot的算法细节实现
本章设置这部分内容主要是 为了稍后介绍各款垃圾收集器时做前置知识铺垫。1、根节点枚举我们以可达性分析算法中从GC Roots集合找引用链这个操作作为介绍虚拟机高效实现的第一个例子。固定可作为GC Roots的节点主要在全局性的引用(例如常量或类静态属性)与执行上下文(例如 栈帧中的本地变量表)中,尽管目标明确,但查找过程要做到高效并非一件容易的事情,现在Java应用越做越庞大,光是方法区的大小就常有数百上千兆,里面的类、常量等更是恒河沙数,若要逐个检查以这里为起源的引用肯定得消耗不少时间。迄今为止,所转载 2020-11-11 22:58:54 · 570 阅读 · 0 评论 -
JVM垃圾回收(GC)
Java内存区域运行时,程序计数器、虚拟机栈、本地方法,栈随线程而生,随线程而灭;栈中的栈帧随着方法的进入和退出而执行着出栈和入栈操作,每一个栈帧中分配多少内存在类结构确定下来时(编译期)大体上是已知的。方法结束或者线程结束时,内存自然就回收了,所以这几个区域就不需要过多考虑内存分配和回收的问题。而Java堆和方法区就不一样,我们只有在程序处于运行期间才知道会需要多少内存,这部分的内存分配和回收都...转载 2019-07-18 11:59:38 · 287 阅读 · 0 评论 -
模拟JVM各数据区内存溢出
在Java虚拟机规范的描述中,除了程序计数器外,虚拟机内存的其他几个运行时区域都有发生 OutOfMemoryError(下文称OOM)异常的可能,本文将通过若干实例来验证异常发生的场景,并且会初步介绍几个与内存相关的最基本的虚拟机参数。1、Java堆溢出Java堆用于存储对象实例,只要不断地创建对象,并且保证 GC Roots到对象之间有可达路径来避免垃圾回收机制清除这些对象,那么在对象...转载 2019-07-17 14:47:35 · 604 阅读 · 0 评论 -
Hotspot虚拟机在堆中对象的分配、布局和访问
1、对象的创建Java是一门面向对象的编程语言,在Java程序运行过程中无时无刻都有对象被创建出来。在语言层面上,创建对象(例如克隆、反序列化)通常仅仅是一个new关键字而已,而在虚拟机中,对象(文中讨论的对象限于普通Java对象,不包括数组和Class对象等)的创建又是怎样一个过程呢?1.1、类加载检查虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到个类的...转载 2019-07-17 16:15:17 · 366 阅读 · 0 评论 -
JVM运行时数据区域
java1.8之前内存区域分为方法区、堆内存、虚拟机栈、本地方法栈、程序计数器。 下图所示:在jdk1.8中,永久代已经不存在,存储的类信息、编译后的代码数据等已经移动到了元空间(MetaSpace)中,元空间并没有处于堆内存上,而是直接占用的本地内存(NativeMemory)。1、程序计数器程序计数器(Program Counter Register)是一块较小的内存空间,它可...转载 2019-07-16 17:40:35 · 844 阅读 · 0 评论