面试题:JVM(一)
1. JVM概述
1.1 JVM的生命周期
说说Java虚拟机的生命周期(阿里)
虚拟机的启动
Java虚拟机的启动是通过引导类加载器(bootstrap class loader)创建一个初始类(initial class)来完成的,这个类是由虚拟机的具体实现指定的。
虚拟机的退出有如下的几种情况:
某线程调用Runtime类或System类的exit方法,或 Runtime类的halt方法,并且Java安全管理器也允许这次exit或halt操作。
程序正常执行结束
程序在执行过程中遇到了异常或错误而异常终止
由于操作系统出现错误而导致Java虚拟机进程终止
1.2 简述JVM
什么是Java虚拟机(墨迹天气)
JVM的组成(凡预科技、杭州比智公司)
JVM的组成(字节跳动)
什么是Java虚拟机(JVM),为什么要使用?(JVM != Japanese Vedio's Man )(阿里)
> 虚拟机:指以软件的方式模拟具有完整硬件系统功能、运行在一个完全隔离环境中的完整计算机系统 ,是物理机的软件实现。常用的虚拟机有VMWare,Visual Box,Java Virtual Machine(Java虚拟机,简称JVM)
1.3 能否画出JVM架构图?
说说Java虚拟机的体系结构?(阿里)
这个架构可以分成三层看:
最上层:javac编译器将编译好的字节码class文件,通过java 类装载器执行机制,把对象或class文件存放在 jvm划分内存区域。
中间层:称为Runtime Data Area,主要是在Java代码运行时用于存放数据的,从左至右为方法区(永久代、元数据区)、堆(共享,GC回收对象区域)、栈、程序计数器、寄存器、本地方法栈(私有)。
最下层:解释器、JIT(just in time)编译器和 GC(Garbage Collection,垃圾回收
2. 字节码概述
2.1 字节码文件是跨平台的么?
Java 虚拟机不和包括 Java 在内的任何语言绑定,它只与“Class 文件”这种特定的二进制文件格式所关联。
无论使用何种语言进行软件开发,只要能将源文件编译为正确的Class文件,那么这种语言就可以在Java虚拟机上执行。可以说,统一而强大的Class文件结构,就是Java虚拟机的基石、桥梁。想要让一个Java程序正确地运行在JVM中,Java源码就必须要被编译为符合JVM规范的字节码。
2.2 哪些类型有对应Class对象?
(1)class:
外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类
(2)interface:接口
(3)[]:数组
(4)enum:枚举
(5)annotation:注解@interface
(6)primitive type:基本数据类型
(7)void
3. Class文件结构
文件结构有几个部分?(百度)
Class文件的结构并不是一成不变的,随着Java虚拟机的不断发展,总是不可避免地会对Class文件结构做出一些调整,但是其基本结构和框架是非常稳定的。
Class文件的总体结构如下:
魔数:class文件的标志
Class文件版本:判断当前JDK版本是否满足编译版本
常量池:字面常量和引用常量存放的地方
访问标识(或标志):修饰符
类索引,父类索引,接口索引集合:实现的接口和继承
字段表集合:类字段
方法表集合:类方法
属性表集合:类属性
4. 字节码指令
4.1 概述
ava字节码对于虚拟机,就好像汇编语言对于计算机,属于基本执行指令。
Java 虚拟机的指令由一个字节长度的、代表着某种特定操作含义的数字(称为操作码,Opcode)以及跟随其后的零至多个代表此操作所需参数(称为操作数,Operands)而构成。由于 Java 虚拟机采用面向操作数栈而不是寄存器的结构,所以大多数的指令都不包含操作数,只有一个操作码。
由于限制了 Java 虚拟机操作码的长度为一个字节(即 0~255),这意味着指令集的操作码总数不可能超过 256 条。
在Java虚拟机的指令集中,大多数的指令都包含了其操作所对应的数据类型信息。例如,iload指令用于从局部变量表中加载int型的数据到操作数栈中,而fload指令加载的则是float类型的数据。
对于大部分与数据类型相关的字节码指令,它们的操作码助记符中都有特殊的字符来表明专门为哪种数据类型服务:
i代表对int类型的数据操作
l代表long类型的数据操作
s代表short类型的数据操作
b代表byte类型的数据操作
c代表char类型的数据操作
f代表float类型的数据操作
d代表double类型的数据操作
也有一些指令的助记符中没有明确地指明操作类型的字母,如arraylength指令,它没有代表数据类型的特殊字符,但操作数永远只能是一个数组类型的对象。
还有另外一些指令,如无条件跳转指令goto则是与数据类型无关的。
大部分的指令都没有支持整数类型byte、char和short,甚至没有任何指令支持boolean类型。编译器会在编译期或运行期将byte和short类型的数据带符号扩展(Sign-Extend)为相应的int类型数据,将boolean和char类型数据零位扩展(Zero-Extend)为相应的int类型数据。与之类似,在处理boolean、byte、short和char类型的数组时,也会转换为使用对应的int类型的字节码指令来处理。因此,大多数对于boolean、byte、short和char类型数据的操作,实际上都是使用相应的int类型作为运算类型。
4.2 面试题
知道字节码吗?字节码指令都有哪些?(百度)
JVM中的字节码指令集按用途大致分成 9 类
加载与存储指令
算术指令
类型转换指令
对象的创建与访问指令
方法调用与返回指令
操作数栈管理指令
控制转移指令
异常处理指令
同步控制指令
在做值相关操作时:
一个指令,可以从局部变量表、常量池、堆中对象、方法调用、系统调用中等取得数据,这些数据(可能是值,可能是对象的引用)被压入操作数栈。
一个指令,也可以从操作数栈中取出一到多个值(pop多次),完成赋值、加减乘除、方法传参、系统调用等等操作。
int a = 1;JVM如何取得a的值(圆通)
局部变量直接从局部变量表获取数据
局部变量表一般直接存储数值或者引用的地址(引用数据类型存地址、基本数据类型存数值)
Integer x = 5;int y = 5;比较 x == y 都经过哪些步骤?(百度)引用类型进行拆箱,后存值进局部变量表,最后取出两个值进行比较
Java虚拟机中,数据类型可以分为哪几类? (阿里)
1. Java虚拟机是通过某些数据类型来执行计算的,数据类型可以分为两种:基本类型和引用类型,基本类型的变量持有原始值,而引用类型的变量持有引用值。2. Java语言中的所有基本类型同样也都是Java虚拟机中的基本类型。但是boolean有点特别,虽然Java虚拟机也把boolean看做基本类型,但是指令集对boolean只有很有限的支持,当编译器把Java源代码编译为字节码时,它会用int或者byte来表示boolean。在Java虚拟机中,false是由整数零来表示的,所有非零整数都表示true,涉及boolean值的操作则会使用int。另外,boolean数组是当做byte数组来访问的。
3. Java虚拟机还有一个只在内部使用的基本类型:returnAddress,Java程序员不能使用这个类型,这个基本类型被用来实现Java程序中的finally子句。该类型是jsr, ret以及jsr_w指令需要使用到的,它的值是JVM指令的操作码的指针。returnAddress类型不是简单意义上的数值,不属于任何一种基本类型,并且它的值是不能被运行中的程序所修改的。
4. Java虚拟机的引用类型被统称为“引用(reference)”,有三种引用类型:类类型、接口类型、以及数组类型,它们的值都是对动态创建对象的引用。类类型的值是对类实例的引用;数组类型的值是对数组对象的引用,在Java虚拟机中,数组是个真正的对象;而接口类型的值,则是对实现了该接口的某个类实例的引用。还有一种特殊的引用值是null,它表示该引用变量没有引用任何对象。
为什么不把基本类型放堆中呢? (阿里)
首先是栈、堆的特点不同。(堆比栈要大,但是栈比堆的运算速度要快。)
将复杂数据类型放在堆中的目的是为了不影响栈的效率,而是通过引用的方式去堆中查找。(八大基本类型的大小创建时候已经确立大小。三大引用类型创建时候无法确定大小)
简单数据类型比较稳定,并且它只占据很小的内存,将它放在空间小、运算速度快的栈中,能够提高效率。
Java中的参数传递是传值呢?还是传引用? (阿里)对于基本数据类型:将实际参数拷贝到形式参数中,故形参的改变并不会引起实参的改变
对于引用数据类型:传递的是引用的内容(地址),故可修改引用内容里面的参数(属性),但无法改变实参指向哪个引用对象(地址)
Java中有没有指针的概念? (阿里)没有指针的概念,但可以说有类似指针的机制,即”引用“
Java中传递引用数据类型时实际传递的就是引用数据所在堆空间的地址,故所谓的形参和实参同时指向那一块空间地址(存储那块空间的地址),形参和实参并没有存储真实的数据,