Java虚拟机(jvm面试宝典,快速熟悉)

一、Java的跨平台特性

Java的跨平台特性是由于JVM才得以实现的,一个.java文件通过编译形成字节码文件(.class文件),这种文件是可以运行在jvm上的,而jvm可以被安装到不同的平台上 ,所以说 java实现了跨平台

二、JVM在哪里?(位置)

JVM是运行在操作系统之上的,与硬件没有直接的交互,但是它可以调用底层的硬件,用JIN(Java本地接口调用底层硬件接口,已经过时了)

三、JVM体系结构

JVM体系结构概览图

四、类装载机制

4.1 概念

4.2 类装载机制的种类

4.3 双亲委派机制

4.4 沙箱安全机制

五、JVM内存模型

根据JVM规范,JVM内存共分为虚拟机栈、程序计数器、本地方法栈、堆、方法区五部分。

jvm内存模型

5.1 java内存区域

线程私有区域:程序计数器、java虚拟机栈、本地方法栈

什么是线程私有?
由于JVM的多线程 是通过轮流切换线程分配处理器执行时间的方式来实现的. 因此在任何一个确定的时刻,一个处理器(多核处理器指的是 一个内核)都只会执行一条线程中的指令。为了切换线程后能恢复到正确的执行位置,每条线程都需要独立的程序计数器,各个线程之间的计数器互不影响,独立存储。我们把类似这类区域称为“线程私有”的内存。

  1. 程序计数器
    1) 程序计数器是一块比较小的内存空间,可以看作是当前线程 所执行的字节码 行号指示器;
    2) 如果当前线程执行的是Java方法,程序计数器记录的是 正在执行的 虚拟机字节码指令地址(代码行数),如果执行的是本地native方法计数器值为空
    3) 程序计数器是唯一一个在JVM规范中没有OOM(OutOfMemoryError,内存溢出)出现的区域;

  2. Java虚拟机栈
    1)描述 java方法执行 的内存模型:
    每个方法都会在 虚拟机栈中 创建一个栈帧用于存储局部变量表、操作数栈、方法出口等信息。每一个方法 从调用到执行完成的过程,就对应 一个栈帧在虚拟机栈中入栈和出栈的过程。
    2) 生命周期与线程相同。

    3)方法的回收不属于垃圾回收。
    4)此区域可能出现的两种异常
    ——当前线程请求的栈深度 > 虚拟机栈深度(-Xss设置栈大小),抛出StackOverflow异常
    ——虚拟机在动态扩展时,无法申请到足够大的内存,抛出OOM(OutOfMemoryError)异常

局部变量表:
·存放了编译器可知的各种基本数据类型(8种)、对象引用
·局部变量表所需的内存空间在编译器完成分配,当进入一个方法时,这个方法 需要需要在帧中分配多大的局部变量 空间是完全确定的,在执行期间不会改变局部变量表的大小;

  1. 本地方法栈
    1)本地方法栈的功能和特点类似于虚拟机栈,都具有线程隔离的特点 以及都能抛出StackOverflowError 和 OOM异常
    2)与虚拟机栈不同的是,本地方法栈服务的对象是JVM执行的native方法,而虚拟机栈服务的是java方法。
线程共享区域:java堆、方法区、运行时常量池
  1. Java堆(GC堆 ,垃圾回收的主要区域
    1)java堆在JVM启动时创建存放的都是对象实例,JVM要求所有的对象实例以及数组都在java堆上存放;
    2)java堆可以处于物理上不连续的区域,java堆一般来说都是可扩展的(-Xms: 设置堆最小值,-Xmx: 设置堆最大值);
    3)如果堆中没有足够的内存来 完成对象实例化 并且 无法再扩展,抛出OOM异常

  2. 方法区(JDK1.8之前称之为永久代,以后称为元空间
    1)存储已被JVM加载类信息、常量、静态变量
    2)此区域也会进行垃圾回收主要针对 常量池的回收 以及 类型卸载;
    3)方法区无法满足内存分配需求时,抛出OOM异常

  3. 运行时常量池(方法区的一部分)
    1)存放字面量符号引用
    字面量:字符串、final常量、基本数据类型的值;
    符号引用:是一个字符串。类和结构的完全限定名、字段的名称和描述符、方法的名称和描述符;

5.2 java堆溢出

Java堆用于存储对象实例,只要不断的创建对象,并且保证 GC Roots 到对象之间有可达路径避免GC清除这些对象,那么在对象数量达到最大堆容量后就会产生内存溢出异常

堆的OOM分为两种情况:内存泄漏 、内存溢出
内存泄漏:泄漏对象无法被垃圾回收;
内存溢出:该对象确实还应该存活,应该对比物理内存查看当前Java堆是否还应扩容 或者 缩短对象存活时间;

六、如何判断对象已死

6.1 引用计数法(会出现循环引用问题)

6.2 可达性分析算法

Java采用“可达性分析” 来判断对象是否存活(同样采用此法的还有C# 、Lisp-最早的一门采用动态内存分配的语言 )。

1)核心 :通过一系列称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径称为“ 引用链 ”,当一个对象到 GC Roots 没有任何的 引用链相连时(从 GC Roots 到这个对象不可达)时,证明此对象不可用

在Java语言中,可作为GC Roots的对象 包含以下几种:
1、虚拟机栈(栈帧中的本地变量表)中引用的对象。
2、方法区中静态属性引用的对象
3、方法区中常量引用的对象
4、本地方法栈中(Native方法)引用的对象

6.3 如何判断对象真正死亡?

1)至少要经历两次标记过程: 如果对象在进行可达性分析之后发现 没有与GC Roots相连接 的引用链(对象不可达),那它将会被 第一次标记 并且进行一次筛选,筛选的条件是此对象是否有必要执行 finalize()方法 。当对象没有覆盖finalize()方法或者finalize()方法已经被JVM调用过 ,虚拟机会将这两种情况都视为"没有必要执行",此时的对象才是真正"死"的对象
如果这个对象被判定为有必要执行finalize()方法,那么这个对象将会被放置在一个叫做F-Queue的队列之中,并在稍后由一个虚拟机自动建立的、低优先级的Finalizer线程去执行它(这里所说的执行指的是虚拟机会触发finalize()方法 )。finalize()方法是对象逃脱死亡的最后一次机会 ,稍后GC将对F-Queue中的对象进行第二次小规模标记,如果对象在finalize()中成功拯救自己 (只需要重新与引用链上的任何一个对象建立起关联关系即可),那在第二次标记 时它将会被移除出"即将回收"的集合;如果对象这时候还是没有逃脱,那基本上它就是真的被回收了。

七、GC 垃圾回收算法

7.1 四大算法

1)引用计数法(会出现循环引用问题,jvm一般不会使用)
2)标记清除(发生在老年代)
3)复制算法(发生在 年轻代中,即Minor GC采用的复制算法,无内存碎片,效率高,内存利用率低)
4)标记整理(也叫标记压缩,发生在老年代,fullGC)
标记-清除-压缩 :减少移动对象的成本,老年代一般使用)

八、垃圾收集器

如果说 垃圾回收算法 是内存回收 的方法论,那么 垃圾收集器 就是内存回收的 具体实现。

不同分代的收集器
上图展示了7种作用于不同分代的收集器,如果两个收集器之间存在连线,就说明他们可以搭配使用

8.1 三个概念

并行(Parallel):

多条垃圾收集线程并行工作,用户线程仍处于等待状态。

并发(Concurrent):

指用户线程与垃圾收集线程同时执行(不一定并行,可能会交替执行),用户程序继续运行,而垃圾收集程序在另一个CPU上。

吞吐量:

就是CPU用于运行用户代码的时间CPU总消耗时间的比值,即吞吐量 = 运行用户代码 / (运行用户代码 + 垃圾收集时间)。如:虚拟机总共运行了100分钟,其中垃圾收集花掉了1分钟,那么吞吐量就是99%。

8.2 Serial 收集器(新生代收集器,串行GC)

8.3 ParNew 收集器(新生代收集器,并行GC)

8.4 Parallel Scavenge收集器(新生代收集器,并行GC)

8.5 Serial Old 收集器(老年代收集器,串行GC)

8.6 Parallel Old 收集器(老年代收集器,并行GC)

8.7 CMS收集器(老年代收集器,并发GC)

8.8 G1收集器(唯一一款全区域的垃圾回收器)

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值