JVM

JVM面试题

  • Java虚拟机是什么?
    运行环境 运行字节码
  • 内存模型
    所有变量存储在主存中 每个线程有自己的工作内存 线程对变量的所有操作必须在工作内存 不能直接读写主存 线程间传递数据需要自己的工作内存和主存之间数据同步
    ThreadLocal和内存模型的关系?
    ThreadLocal存储的value其实就是工作内存的变量副本拷贝
  • 分区
    栈和堆区别?
    存放内容不同
    栈 线程私有
    堆 线程共享
    栈:
    1⃣️ Java虚拟机栈
    线程私有 生命周期同线程
    每个方法都会创建一个栈帧 方法的调用到执行完对应着栈帧从入栈到出栈的过程
    通常说的栈就是指局部变量表(编译器分配 进入一个方法时 局部变量表的内存大小是确定的) 存储8种基本数据类型 变量引用以及指令地址
    两种异常:StackOverFlowError(线程请求深度大于虚拟机允许的深度)和OutOfMemoryError(虚拟机动态扩展到无法申请到足够内存空间)
    2⃣️ 本地方法栈
    虚拟机栈服务字节码 本地方法栈服务Native方法

堆:
所有线程共享区域 唯一目的:存放对象实例
通常分为 新生代和老年代

方法区:
线程共享 存放已经被加载的类信息 常量 静态变量
堆的一个逻辑部分(永久代)
程序计数器:
字节码的行号指示器 通过改变程序计数器确定下一条指令 线程私有 无OOM

  • GC两种判定方法
    1⃣️ 引用计数
    JDK1.2之前使用的
    引用计数器+1 -1的操作 但是无法解决对象之间循环引用 为什么?

2⃣️ 可达性分析
从GC Root的节点开始向下找 一个对象到GC Root没有任何引用链连接 则证明可回收
GC Root对象包括:
虚拟机栈种中引用的对象;方法区中静态属性和常量引用的变量;本地方法栈中引用的对象

  • GC三种收集方法
    1⃣️ 标记清除
    从根开始 标记所有可达对象 其余没有标记的执行清除
    存在两个弊端:
    效率不高;回收后空间不连续 造成内存碎片
    适用于存活对象较多的情况
    2⃣️ 复制
    从根开始扫描 将存活对象复制到新的空间 空间换时间
    适用于存活对象比较少的情况 老年代一般不能直接使用这种算法
    新生代和老年代的区别?
    新生代指生命周期比较短的对象 老年代指生命周期比较长的对象
    3⃣️ 标记整理
    标记后不直接清理可回收对象 而是让所有存活对象往一端移动 然后清除边界以外的内存
    成本更高 但是解决了内存随便的问题

  • 类加载的五个过程
    1⃣️ 加载
    全限定名获取获取二进制字节流;
    将字节流代表的静态存储结构转化为方法区域的运行时数据结构;
    在Java堆中生成Class对象 作为方法区域数据访问的入口
    2⃣️ 验证
    保证Class字节流符合JVM的规范
    文件格式验证;
    元数据验证;
    字节码验证;
    符号引用验证
    3⃣️ 准备
    为类变量(static修饰)分配内存并初始化 非final修饰的初始化为0 而非真实值
    4⃣️ 解析
    将常量池中的符号引用替换成真实引用
    主要包括四个:类或接口解析;字段解析;方法解析;接口方法解析
    5⃣️ 初始化
    由代码初始化类的变量和其他资源

  • 双亲委派模型
    启动类加载器 BootsTrap;扩展类加载器 Extension ;应用程序类加载器 Application
    双亲委派模型要求除了启动类加载器外其他的加载器都必须有父类(组合实现)
    工作过程:
    先把加载请求委托给父类 每一层都是这样 因此加载请求会传到顶层的启动类加载器 当父类无法完成子类才自己加载

好处:
Java类随着类加载器有了优先级的层级关系
同一个Class文件被不同的类加载器加载 也是不同类

实现自己的机载器:继承ClassLoader并实现findClass方法

你可能感兴趣的:(JVM)