JVM面试题

谈谈对Java的理解

  • 平台无关性
  • GC
  • 语言特性(泛型,反射,lambda等)
  • 面向对象
  • 类库
  • 异常处理

Java的平台无关性

Java源码首先被编译成字节码,再由不同平台的JVM进行解析,Java语言在不同的平台上运行时不需要重新编译,Java虚拟机在执行字节码的时候,把字节码转换成具体平台上的机器指令。

JVM如何加载.class文件

JVM架构图

  • Class Loader:根据特定的格式,加载class文件到内存
  • Execution Engine:对命令进行解析
  • Native Interface:融合不同开发语言的原生库为Java所用
  • Runtime Data Area:JVM内存空间模型

谈谈反射

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

ClassLoader的种类

  • BootStrapClassLoader:C++编写,加载核心库java.*
  • ExtClassLoader:java编写,加载扩展库javax.*
  • AppClassLoader:java编写,加载程序所在目录(项目中的src)
  • 自定义ClassLoader:java编写,定制化加载

双亲委派机制

参考的博客

当某个类加载器需要加载某个.class文件时,它首先把这个任务委托给他的上级类加载器,递归这个操作,如果上级的类加载器没有加载,自己才会去加载这个类。

作用

  1. 防止重复加载同一个.class。通过委托去向上面问一问,加载过了,就不用再加载一遍。保证数据安全。

  2. 保证核心.class不能被篡改。通过委托方式,不会去篡改核心.clas,即使篡改也不会去加载,即使加载也不会是同一个.class对象了。不同的加载器加载同一个.class也不是同一个Class对象。这样保证了Class执行安全。

谈谈ClassLoader

ClassLoader在Java中有着非常重要的作用,它主要工作在Class装载的加载阶段,其主要作用是从系统外部获得Class二进制数据流。它是Java的核心组件,所有的Class都是由ClassLoader进行加载的,ClassLoader负责通过将Class文件里的二进制数据流装载进系统,然后交给Java虚拟机进行连接、初始化等操作。

类加载的方式

  • 隐式加载:new
  • 显式加载:loadClass,forName

类的装载过程

loadClass和forName的区别

  • 使用Class.forName(className)装载class会对相应的类进行初始化,即上图类的装载过程的第三步
  • 使用ClassLoader.loadClass(className)装载class,则只会进行上图的第一步,不会进行链接

总结

​ 一般情况下,这两个方法效果一样,都能装载Class。但如果程序依赖于Class是否被初始化,就必须用Class.forName(className)了。

​ 如:jdbc中的Driver注册时只能用Class.forName(className)

因为,Driver在static块中会注册自己到java.sql.DriverManager。而static块就是在Class的初始化中被执行。所以这个地方就只能用Class.forName(className)。

JVM内存模型

线程私有部分:程序计数器、虚拟机栈、本地方法栈

  • 程序计数器

    • 当前线程所执行的字节码行号指示器(逻辑)(多线程时,上下文切换,依靠程序计数器来恢复正确的执行位置)
    • 改变计数器的值来选取下一条需要执行的字节码指令
    • 和线程是一对一的关系即“线程私有”
    • 对Java方法计数,如果是Native方法则计数器值为Undefined
    • 不会发生内存泄漏
  • 虚拟机栈

    • Java方法执行的内存模型
    • 包含多个栈帧
    • 局部变量表和操作数栈
      • 局部变量表:包含方法执行过程中的所有变量
      • 操作数栈:入栈、出栈、复制、交换、产生消费变量(用来执行加减乘除等操作)
  • 本地方法栈

    • 本地方法栈和java虚拟机栈十分相似,差别不过是java虚拟机栈是为了java虚拟机执行字节码所服务,而本地方法栈则是为了执行native方法所服务的,所以本地方法也是一个私有的内存区域,也是后进先出栈,作用是支撑native方法的调用,执行和退出与java虚拟机栈一样也会出现以上两种异常。

线程共享部分:共享部分为:MetaSpace(元空间),Java堆

  • 元空间(MetaSpace)与永久代(PermGen)的区别:(用元空间代替永久代)

    • 元空间使用的是本地内存,而永久代使用的是jvm的内存
    • 字符串常量池存在永久代中,容易出现性能问题和内存溢出
    • 类和方法的信息大小难以确定,给永久代的大小指定带来困难
    • 永久代会为GC带来不必要的复杂性
  • Java堆(Heap),在虚拟机启动时创建

    • 对象实例的分配区域(Java堆的唯一目的)
    • GC管理的主要区域

JVM三大性能调优参数

  • -Xss:规定了每个线程虚拟机栈的大小
  • -Xms:堆的初始值
  • -Xmx:堆能达到的最大值

Java内存模型中堆和栈的区别

  • 联系:引用对象、数组时,栈里定义变量保存堆中目标的首地址

  • 区别

    • 管理方式:栈自动释放,堆需要GC
    • 空间大小:栈比堆小
    • 内存碎片相关:栈产生的碎片远小于堆
    • 分配方式:栈支持静态和动态分配,而堆仅支持动态分配
    • 效率:栈的效率比堆高
原文地址:https://www.cnblogs.com/shouyaya/p/13523714.html