java虚拟机问题1

1.java为什么要在虚拟机里执行


  1. java虚拟机将java程序编译为java字节码,java字节码可以在有java虚拟机的机器上执行。具备可移植性

2.java虚拟机是怎么执行字节码的?


  1. java代码被编译成class文件,加载到java虚拟机中。java类会被放在方法区中,运行时会执行方法区中的代码。

  2. java虚拟机会将栈细分为java方法栈,本地方法栈,PC寄存器。

  3. 运行时,调用java方法时,会在当前线程的java方法中生成一个栈帧,退出方法的时候会弹出当前栈帧。

  4. 上述编译过程有两种形式:1,解释执行,逐条将字节码翻译为机器码(优势:无需等待编译);2,即时编译,将一个方法中包含的所有字节码编译成机器码(优势:执行速度快)。

3.java虚拟机的运行效率


  1. HotSpot采用混合编译,以二八原则为基础

  2. 先解释执行,然后将热点代码进行即时编译,编译执行。即时编译器有两种C1(Client编译器,编译时间短),C2(Server编译器,执行效率高),即时编译的时候,会先由C1编译器编译,然后会将热点中的热点代码再次用C2编译。

4.java虚拟机是如何加载java类的

  1. java虚拟机加载java类,其实就是java虚拟机将字节流转化为java类的过程。这个过程可分为三步:加载,链接,初始化。

  2. 加载,是指查找字节流,并据此创建类的过程。类加载器使用了双亲委派模型

  3. 链接,只是将创建成的类合并到java虚拟机中,使之能够执行的过程。链接还分为:验证,准备,解析三个步骤。

  4. 初始化,是为常量值的字段复制的过程,并且会执行初始化的clinit方法。类的初始化仅会被执行一次。

5.重载与重写

  1. 在 Java程序里,如果同一个类中出现多个名字相同,并且参数类型也相同的方法,那么它是无法通过编译的,所以如果再有面试官问,如果方法名和参数类型以及个数都相同,但是返回值不同,是重载吗?答案是编译都不通过,重载个毛线。

  2. 重载:方法名相同,参数类型不同。其中参数类型不同指的是按顺序的类型不同,例如string,int和int,String就是不同的参数类型。

  3. 重写:方法名相同,参数类型也相同重写肯定是有父子关系的方法覆盖。

  4. 一定要记得,和返回值类型毫无关系。

6.java虚拟机虚方法的调用

  1. java中方法调用的指令

invokevirtual非私有实例方法动态绑定
invokeinterface接口方法调用动态绑定
invokestatic调用静态方法静态绑定
invokespecial调用构造器、私有实例方法以及超类非私有实例方法静态绑定
  1. 虚方法调用一般指的是多态这种情况

  2. 方法内联指的是将目标方法的字节码直接编译到原方法中

  3. 在虚方法调用的时候,会采用单态内联缓存,会记住上一次调用的目标方法地址,如果下一次还是调用对应的方法,则会直接利用缓存,调用对应的目标方法地址。但是如果不同,则会去方法表中寻找对应的目标方法并调用,但是还会增加额外的开销,修改内联缓存。

  4. 虚方法调用包括 invokevirtual 指令和
    invokeinterface指令。如果这两种指令所声明De 目标方法被标记为 final,那么 Java 虚拟机会采用静态绑定。否则,Java 虚拟机将采用动态绑定,在运行过程中根据调用者的动态类型,来决定具体的目标方法。Java 虚拟机的动态绑定是通过方法表这一数据结构来实现的。方法表中每一个重写方法的索引值,与父类方法表中被重写的方法的索引值一致。在解析虚方法调用时,Java 虚拟机会纪录下所声明的目标方法的索引值,并且在运行过程中根据这个索引值查找具体的目标方法。Java 虚拟机中的即时编译器会使用内联缓存来加速动态绑定。Java 虚拟机所采用的单态内联缓存将纪录调用者的动态类型,以及它所对应的目标方法。当碰到新的调用者时,如果其动态类型与缓存中的类型匹配,则直接调用缓存的目标方法。否则,Java 虚拟机将该内联缓存劣化为超多态内联缓存,在今后的执行过程中直接使用方法表进行动态绑定。

7.异常机制

  1. 异常的处理方法:捕获异常和抛出异常

  2. 抛出异常分为显示和隐式两种。显示为throw抛出,隐式为Java虚拟机在执行过程中,碰到无法继续执行的异常状态,自动抛出异常。

  3. 所有异常的公共父类是Throwable。其有两大子类:Error,执行状态无法恢复,需要终止线程或者虚拟机;Exception,包含可能需要捕获的异常。Exception又有一种特殊的异常为RuntimeException。

  4. 异常的另一种分类方式为:checkException和UncheckException。其中RuntimeException和Error都属于是UncheckException。其余异常都属于是CheckException,在触发的时候需要显示的捕获,或者用throw关键字抛出。

8.try catch finally问题

  1. try 代码块:用来标记需要进行异常监控的代码。

  2. catch 代码块:跟在 try 代码块之后,用来捕获在 try 代码块中触发的某种指定类型的异常。除了声明所捕获异常的类型之外,catch 代码块还定义了针对该异常类型的异常处理器。在 Java 中,try 代码块后面可以跟着多个 catch 代码块,来捕获不同类型的异常。Java 虚拟机会从上至下匹配异常处理器。因此,前面的 catch 代码块所捕获的异常类型不能覆盖后边的,否则编译器会报错。

  3. finally 代码块:跟在 try 代码块和 catch 代码块之后,用来声明一段必定运行的代码。它的设计初衷是为了避免跳过某些关键的清理代码,例如关闭已打开的系统资源。

  4. 在程序正常执行的情况下,这段代码会在 try 代码块之后运行。否则,也就是 try 代码块触发异常的情况下,如果该异常没有被捕获,finally 代码块会直接运行,并且在运行之后重新抛出该异常。

  5. 如果该异常被 catch 代码块捕获,finally 代码块则在 catch 代码块之后运行。在某些不幸的情况下,catch 代码块也触发了异常,那么 finally 代码块同样会运行,并会抛出 catch 代码块触发的异常。在某些极端不幸的情况下,finally 代码块也触发了异常,那么只好中断当前 finally 代码块的执行,并往外抛异常。

9.jvm是如何实现反射的

  1. 在默认的情况下,方法的反射调用为委派实现,委派给本地实现来进行方法调用。在调用过15次之后,委派实现便会将对象切换至动态实现。

  2. 方法的反射调用会带来不少的性能开销,原因主要有三个:变长参数导致的Object数组,基本类型的自动装箱,拆箱,还有最重要的方法内联。

10.jvm垃圾回收

  1. jvm的垃圾辨别方法:

引用计数器法,给每个对象添加一个引用计数器,用来统计指向该对象的引用个数,一旦某个对象的引用计数器为0,则说明该对象死亡,可以被回收。

引用计数器法的缺点,需要额外的空间来存储计数器,并且会有频繁的更新操。另外一个重大的漏洞就是,无法解决循环依赖的问题,即a依赖b,b也依赖a。

可达性分析算法,将一系列的GCRoot作为初始存活对象的集合,从该集合出发,探索所有能够被该集合引用到的对象,并且做标记。未被探索到的对象便是死亡的对象,可以被回收。

GCRoot:可以暂时理解为由堆外指向堆内。
包括但不限于:java方法栈中的局部变量,已加载类的静态变量,已启动且未停止的java线程,JNI调用本地方法。

  1. 常见的三种垃圾回收算法:

标记清除法:
把死亡对象所占据的内存标记为空闲内存,并记录在空闲列表中。在需要新建对象时,内存管理模块便会从该空闲列表中寻找空闲内存,并划分给新对象。缺点,容易出现内存碎片,并且如果突然出现一个大对象的话,这些不连续的小内存空间将,无法分配大对象。

标记压缩法:
把存活的对象聚集到内存区域的起始位置,从而留下连续的内存空间。能够解决内存碎片化的问题,但是压缩算法会有性能开销。

复制算法:
将内存区域划分为两等分。分别用from,to指针来维护。并且只用from指针指向的内存区域来划分内存。当发生垃圾回收的时候,便把存活的对象复制到to指针区域,并且交换from和to指针的内容。缺点:内存利用率低下。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值