面试官问我对java虚拟机了解吗?我给他了满分的回答

java的内存区域

(如需要牛客网的java面经电子版本,可以加个关注,私信我,免费分享)
在这里插入图片描述
1.程序计数器
程序计数器是一块较小的内存空间,它可以看做是当前线程所执行的字节码的行号指示器。在虚拟机的概念模型里,字节码解释工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令。

2.java虚拟机栈
与程序计数器一样,java虚拟机栈也是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每个方法从调用到执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。

3.本地方法栈
本地方法栈与虚拟机栈的作用是相似的,他们之间的区别是虚拟机执行的是java方法,而本地方法栈则为虚拟机使用到的Native方法服务。

4.java堆
java堆是java虚拟机所管理的内存中最大的一块,java堆是所有线程共享的一块区域内存。它存在的目的就是用来存放对象实例的。所有的对象实例以及数组都要在堆上分配。

5.方法区
方法区域java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

6.运行时常量池
运行时常量池是方法区的一部分。class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放编译期生成的各种字面量和符号引用。

垃圾收集器与内存分配策略

对象已死吗

在堆里面存放着Java世界中几乎所有的对象实例,垃圾收集器在对堆进行回收前,第一件事情就是要确定这些对象之中哪些还“存活”着,哪些已经“死去”(即不可能再被任何途径使用的对象)。
1.引用计数算法
给对象中添加一个引用计数器,每当有一个地方引用时,计数器值加1,当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用。

2.可达性分析算法
这个算法的基本思想就是通过一系列的"GC ROOT"的对象作为起点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC ROOTS没有任何引用链想连时,则认为此对象不可用。
在这里插入图片描述
在java语言中,可作为GC ROOTS的对象包括下面几种:

  1. 虚拟机栈中引用的对象
  2. 方法区中类静态属性引用的对象
  3. 方法区中常量引用的对象
  4. 本地方法栈中引用的对象
垃圾收集算法

1.标记清除算法
在这里插入图片描述
标记——清除算法将垃圾回收分为两阶段:标记阶段和清除阶段。在标记阶段首先通过根节点,标记所有从根节点开始的对象,未被标记的对象就是未被引用垃圾对象。然后,在清除阶段,清除所有未被标记的对象。标记清除算法带来的一个问题是会存在大量的空间碎片,因为回收的空间是不连续的
==小结:==速度快但会产生内部碎片

2.标记整理
在这里插入图片描述
标记-压缩算法是一种老年代的回收算法,它在标记-清除算法的基础上做了一些优化。首先也需要从根节点开始对所有可达对象做一次标记,但之后,它并不简单的清理未标记的对象,而是将所有的存活对象压缩到内存的一端。之后,清理边界外的所有空间。这种方法避免了碎片的产生。因此,它的性价比比较高
==小结:==速度慢,但是没有内部碎片

3.复制算法
将现有的内存空间分为两块,每次只使用其中的一块,在垃圾回收是将正在使用的内存中的存活对象复制到未被使用的内存块中,之后,清除正在使用的内存块中的所有对象,交换两个内存的角色,完成垃圾回收。
不会有内部碎片,但是会占用双倍的内存
在这里插入图片描述
在这里插入图片描述

4.分代的垃圾回收机制
在这里插入图片描述

  1. 对象首先分配在伊甸园区域
  2. 新生代空间不足时,触发minor gc,伊甸园和from存活的对象使用copy复制到to中,存活的对象年龄加1并且交换from to
  3. minor gc会引发stop the world,暂停其他用户的线程,等垃圾回收结束,用户线程才恢复
  4. 当对象寿命超过阙值时,会晋升至老年代,最大寿命是15
  5. 当老年代空间不足,会尝试触发minor gc,如果之后空间仍不足,那么触发full gc。STW(响应)的时间更长。

当前商业虚拟机的垃圾收集都采用“分代收集”(Generational Collection)算法,这种算法并没有什么新的思想,只是根据对象存活周期的不同将内存划分为几块。一般是把Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。而老年代中因为对象存活率高、没有额外空间
对它进行分配担保,就必须使用“标记—清理”或者“标记—整理”算法来进行回收。

Minor GC和Full GC有什么不一样吗?
新生代GC(Minor GC):指发生在新生代的垃圾收集动作,因为Java对象大多都具备朝生夕灭的特性,所以Minor GC非常频繁,一般回收速度也比较快。
老年代GC(Major GC/Full GC):指发生在老年代的GC,出现了Major GC,经常会伴随至少一次的Minor GC(但非绝对的,在Parallel Scavenge收集器的收集策略里就有直接进行Major GC的策略选择过程)。Major GC的速度一般会比Minor GC慢10倍以上。

垃圾收集器

如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。Java虚拟机规范中对垃圾收集器应该如何实现并没有任何规定,因此不同的厂商、不同版本的虚拟机所提供的垃圾收集器都可能会有很大差别,并且一般都会提供参数供用户根据自己的应用特点和要求组合出各个年代所使用的收集器。
在这里插入图片描述
1.Serial收集器
Serial收集器是最基本的收集器,这个收集器是一个单线程的收集器,但它的单线程的意义并不仅仅说明他只会使用一个CPU或一条收集线程去完成垃圾收集工作,更重要的是在它进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束。

2.ParNew收集器
ParNew收集器其实就是Serial收集器的多线程版本,除了使用多条线程进行垃圾收集以外,其他行为都和Serial收集器一样。

3.Parallel Scavenge收集器
Parallel Scavenge收集器是一个新生代收集器,它的关注点与其他收集器不同,CMS等收集器的关注点是尽可能的缩短垃圾收集时用户线程停顿的时间,而Parallel Scavenge收集器的目标是达到一个可控制的吞吐量。

4.Serial Old收集器
Serial Old收集器是serial收集器的老年代版本,它同样是一个单线程收集器,这个收集器的主要意义:在于给Cinent模式下的虚拟机使用。

5.Parallel Old收集器
Parallel Old收集器是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法。

6.CMS收集器
CMS收集器是一种以获取最短回收停顿时间为目标的收集器。
CMS收集器是基于、“标记-清除”算法,整个过程分为4个步骤:

  1. 初始标记
  2. 并发标记
  3. 重新标记
  4. 并发清除
    其中,初始标记、重新标记这两个步骤仍然需要“Stop The World”。初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快,并发标记阶段就是进行GC RootsTracing的过程,而重新标记阶段则是为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远比并发标记的时间短。

7.G1收集器
G1(Garbage-First)收集器是当今收集器技术发展的最前沿成果之一。
与其他GC收集器相比,G1具备如下特点:

  • 并行与并发:G1能充分利用多CPU、多核环境下的硬件优势,使用多个CPU(CPU或者CPU核心)来缩短Stop-The-World停顿的时间,部分其他收集器原本需要停顿Java线程执行的GC动作,G1收集器仍然可以通过并发的方式让Java程序继续执行。
  • 分代收集:与其他收集器一样,分代概念在G1中依然得以保留。虽然G1可以不需要其他收集器配合就能独立管理整个GC堆,但它能够采用不同的方式去处理新创建的对象和已经存活了一段时间、熬过多次GC的旧对象以获取更好的收集效果。
  • 空间整合:与CMS的“标记—清理”算法不同,G1从整体来看是基于“标记—整理”算法实现的收集器,从局部(两个Region之间)上来看是基于“复制”算法实现的,但无论如何,这两种算法都意味着G1运作期间不会产生内存空间碎片,收集后能提供规整的可用内存。这种特性有利于程序长时间运行,分配大对象时不会因为无法找到连续内存空间而提前触发下一次GC。
  • 可预测的停顿:这是G1相对于CMS的另一大优势,降低停顿时间是G1和CMS共同的关注点,但G1除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒,这几乎已经是实时Java(RTSJ)的垃圾收集器的特征了。

垃圾收集器参数总结
在这里插入图片描述
在这里插入图片描述

类文件结构

class类文件的结构

1.魔术与Class文件的版本
每个class文件的头4个字节称为魔术,它的唯一作用是确定这个文件是否为一个能被虚拟机接受的class文件。
紧接着魔术的4个字节存储的是class文件的版本号:第5个和第6个字节是次版本号,第7个第8个是主版本号。

2.常量池
紧接着主次版本号之后的是常量池入口,常量池可以理解为class文件之中的资源仓库,她是class文件结构中与其他项目关联最多的数据类型,也是占用class文件空间最大的数据项目之一。
常量池中主要存放两大类产量:字面量和符号引用。字面量比较接近java语言层面的常量概念,如文本字符串等。而符号引用则属于编译原理方面的概念,包括了下面三类常量:

  • 类和接口的全限定名
  • 字段的名称和描述符
  • 方法的名称和描述符

3.方法标志
在常量池结束之后,紧接着的两个字节代表访问标志,这个标志用于识别一些类或者接口层面的访问信息,包括:这个class是类还是接口,是否定义为public类型等。

4.类索引、父类索引、接口索引集合
类索引用于确定这个类的全限定名,父类索引用于确定这个类的父类的全限定名,接口索引集合用来描述这个类实现了哪些接口。
类索引、父类索引、接口索引集合都按顺序排列在访问标志之后。

5.字段表集合
字段表集合用于描述接口或者类中声明的变量

6.方法表集合
方法表的结构依次包含 了 访问标志、名称索引、描述符索引、属性表集合等。

7.属性表集合
用于描述某些场景专有的信息

虚拟机类加载机制

类加载的时机

类从被加载到虚拟机内存中开始,它的生命周期包括:加载、验证、准备、解析、初始化、使用和卸载7个阶段。其中验证、准备、卸载3个阶段部分统称为连接
在这里插入图片描述
什么情况下开始类加载的过程?

  1. 遇到new,getstatic,putstatic,invokestatic这4条字节码指令时,如果类没有进行过初始化,则需要先触发其初始化。
  2. 使用java.lang.reflect包含的方法对类进行反射调用的时候
  3. 当初始化一个类的时候,如果发现父类还没有进行初始化,则需要先触发其父类的初始化
  4. 当虚拟机启动时,用户需要指定一个要执行的主类,虚拟机会先初始化这个主类
类加载的过程解析

类加载过程也就是加载、验证、准备、解析和初始化这5个阶段执行的具体动作

1.加载
“加载”是“类加载”过程的一个阶段,在加载阶段,虚拟机要完成以下3件事情:

  1. 通过一个类的全限定名来获取定义此类的二进制字节流
  2. 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
  3. 在内存中生成一个代表这个类的java.lang.class对象,作为方法区这个类的各种数据的访问入口

2.验证
验证是连接阶段的第一步,这个阶段的目的是为了确保class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机的自身安全

3.准备
准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些变量所使用的内存都将在方法区中进行分配。

4.解析
解析阶段是虚拟机将常量内的符号引用替换为直接引用的过程

5.类初始化
类初始化阶段是类加载过程的最后一步,到了初始化阶段,才真正开始执行类中定义的java程序代码。

类加载器

虚拟机设计团队把类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类。实现这个动作的代码模块称为“类加载器”。

1.类与类加载器
类加载器虽然只用于实现类的加载动作,但它在Java程序中起到的作用却远远不限于类加载阶段。对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在Java虚拟机中的唯一性,每一个类加载器,都拥有一个独立的类名称空间。这句话可以表达得更通俗一些:比较两个类是否“相等”,只有在这两个类是由同一个类加载器加载的前提下才有意义,否则,即使这两个类来源于同一个Class文件,被同一个虚拟机加载,只要加载它们的类
加载器不同,那这两个类就必定不相等。

2.双亲委派模型
==双亲委派模型的工作过程是:==如果一个类加载器收到类加载的请求,它首先不会自己去尝试加载这个类,而是把请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求时,子加载器才会尝试自己去加载。
使用双亲委派模型来组织类加载器之间的关系,有一个显而易见的好处就是Java类随着它的类加载器一起具备了一种带有优先级的层次关系。

			java虚拟机,就写这么多吧,如果觉得还可以,记得加个关注奥!!
								帅气的远远啊
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值