【面试】总结常见的JVM面试考点,试试看能答出几道?

一 怎么样确定这个对象已经死了

1)引用计数算法

        给对象添加一个引用计数器,每当一个地方引用它时候,计数器就加1,当引用失效,计数器就减1;任何时刻计数器为0的对象就是不可能再被使用了。这种方法实现简单,效率高,但很难解决对象的循环引用问题。

2)可达性分析算法

        这个算法的基本思路是通过一系列称为“GC Roots”(一组必须活跃的引用)作为起始点,从这些节点开始向下搜索,搜索走过的路径称为引用链,当一个对象到GC Roots没有任何引用链的时候,那么证明此对象是不可用的。

        在Java语言中,做作为GC Roots的对象包括以下几种:

a.虚拟机栈(栈帧中的本地变量表)中引用的对象。

b.方法区中类静态属性引用的对象。

c.方法区中常量引用的对象。

d.本地方法栈JNI(即一般说的Native方法)引用的对象。

二 JVM的运行时数据区域

        Java程序运行时,JVM会将其所管理的内存划分成若干个区域,统称为运行时数据区。其中,部分线程共享的区域会随着JVM的启动而创建,JVM的退出而销毁;而一些线程私有的区域会随着线程的开始而创建,线程的结束而销毁。运行时数据区具体包括程序计数器、Java虚拟机栈、本地方法栈、方法区、堆五个部分。

  • 程序计数器:线程私有的,是一块很小的内存空间,作为当前线程的行号指示器,用于记录当前虚拟机正在执行的线程指令地址;

  • 虚拟机栈:线程私有的,每个方法执行的时候都会创建一个栈帧,用于存储局部变量表、操作数、动态链接和方法返回等信息,当线程请求的栈深度超过了虚拟机允许的最大深度时,就会抛出StackOverFlowError;

  • 本地方法栈:线程私有的,保存的是native方法的信息,当一个jvm创建的线程调用native方法后,jvm不会在虚拟机栈中为该线程创建栈帧,而是简单的动态链接并直接调用该方法;

  • :java堆是所有线程共享的一块内存,几乎所有对象的实例和数组都要在堆上分配内存,因此该区域经常发生垃圾回收的操作;

  • 方法区:存放已被加载的类信息、常量、静态变量、即时编译器编译后的代码数据。即永久代,在jdk1.8中不存在方法区了,被元数据区替代了,原方法区被分成两部分;1:加载的类信息,2:运行时常量池;加载的类信息被保存在元数据区中,运行时常量池保存在堆中;

三 常见的垃圾收集算法

1)标记—清除算法:首先标记出所有需要回收的对象,在标记完成后,统一回收所有被标记的对象,也可以标记存活的对象,再统一回收所有未被标记的对象。标记过程就是对象是否属于垃圾的判定过程。其缺点主要是执行效率不够稳定以及内存空间的碎片化问题。

2)标记——复制算法:简称复制算法,将可用内存按容量分成大小相等的两块,每次只使用其中一块,内存用完时就将依旧存活的对象复制到另一块,再把已使用的内存一次性清理掉。这种算法实现简单,运行高效,但可用空间缩小到原来的一半,空间浪费过大。

3)标记——整理算法:其标记过程同标记—清除算法,但后续步骤是让所有存活的对象都向内存空间一端移动,然后清理掉边界以外的内存。

四 简述一下三色标记什么用来解决什么问题

        在判断对象是否存活时并进行垃圾收集时,可以从GCRoots 节点开始扫描整个引用链,找到所有可达的对象,之后扫描整个引用链的不可达对象,然后将垃圾对象清除掉。但这就导致整个应用程序必须停止,不能做任何改变。为了解决这个问题,就出现了三色标记算法。

        三色标记算法指将所有对象分为白色、黑色和灰色三种类型。黑色表示从 GCRoots 开始,已扫描过它全部引用的对象,灰色指的是扫描过对象本身,还没完全扫描过它全部引用的对象,白色指的是还没扫描过的对象。在实现根可达算法时,将整个过程拆分成了初始标记、并发标记、重新标记、并发清除四个阶段。初始标记阶段,指标记 GCRoots 直接引用的节点,将它们标记为灰色,这个阶段需要整个应用程序停止;并发标记阶段,指从灰色节点开始,去扫描整个引用链,然后将它们标记为黑色,这个阶段不需要应用程序停止;重新标记阶段,指去校正并发标记阶段的错误,这个阶段需要应用程序停止;并发清除,指的是将已经确定为垃圾的对象清除掉,这个阶段不需要应用程序停止。

        三色标记算法通过将最耗时的引用链扫描剥离出来作为并发标记阶段,将其与用户线程并发执行,从而极大地降低了 GC 停顿时间。

六 cms和g1收集器

        CMS收集器是一种以获取最短回收停顿时间为目标的收集器,基于并发“标记清理”实现,在标记清理过程中不会导致用户线程无法定位引用对象。仅作用于老年代收集。它的步骤如下:

1)初始标记:独占CPU,stop-the-world, 仅标记GCroots能直接关联的对象,速度比较快;

2)并发标记:可以和用户线程并发执行,通过GCRoots Tracing 标记所有可达对象;

3)重新标记:独占CPU,stop-the-world, 对并发标记阶段用户线程运行产生的垃圾对象进行标记修正,以及更新逃逸对象;

4)并发清理:可以和用户线程并发执行,清理在重复标记中被标记为可回收的对象。

        CMS收集器的优点是支持并发收集,低停顿,达到近似并发的目的。但其对CPU资源敏感,在CPU资源不足的情况下应用会有明显的卡顿。且无法处理浮动垃圾,会产生大量内存碎片。

        G1收集器弱化了CMS原有的分代模型,将堆内存划分成一个个Region,使得进行收集时不必在全堆范围内进行。它主要特点在于达到可控的停顿时间,用户可以指定收集操作在多长时间内完成,即G1提供了接近实时的收集特性。其步骤如下:

1)初始标记:标记一下GC Roots能直接关联到的对象,伴随着一次普通的Young GC发生,并修改NTAMS(Next Top at Mark Start)的值,让下一阶段用户程序并发运行时,能在正确可用的Region中创建新对象,此阶段是stop-the-world操作。

2)根区间扫描,标记所有幸存者区间的对象引用,扫描 Survivor到老年代的引用,该阶段必须在下一次Young GC 发生前结束。

3)并发标记:是从GC Roots开始堆中对象进行可达性分析,找出存活的对象,这阶段耗时较长,但可与用户程序并发执行,该阶段可以被Young GC中断。

4)最终标记:是为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录,虚拟机将这段时间对象变化记录在线程Remembered Set Logs里面,最终标记阶段需要把Remembered Set Logs的数据合并到Remembered Set中,此阶段是stop-the-world操作,使用snapshot-at-the-beginning (SATB) 算法。

5)筛选回收:首先对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划,回收没有存活对象的Region并加入可用Region队列。这个阶段也可以做到与用户程序一起并发执行,但是因为只回收一部分Region,时间是用户可控制的,而且停顿用户线程将大幅提高收集效率。        

        G1收集器的特点是并行与并发,使用多CPU来缩短Stop-The-world的时间,分代收集,能够自己管理不同分代内已创建对象和新对象的收集。不会产生内存碎片。

七 什么是双亲委派模型

        双亲委派模型是各种类加载器之间的层次关系,其要求除了顶层的启动类加载器外,其余的类加载器都应有自己的父类加载器,但这里类加载器之间的父子关系通常是使用组合关系来复印父加载器的代码。

        其工作过程为:如果一个类加载器收到了来加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此加载请求最终都应该传送到最顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求时,子加载器才会尝试自己去完成加载。

八 类加载流程是什么

        类加载过程就是将.class文件中类的元信息加载进内存,创建Class对象并进行解析、初始化类变量等的过程,分为加载、连接、初始化三个部分。

        类的加载是将.class文件的二进制字节流读入内存,并在堆内存中创建Class对象,作为.class进入内存后的数据的访问入口。在这里只是读入二进制字节流,后续的验证阶段就是要拿二进制字节流来验证.class文件,验证通过,才会将.class文件转为运行时数据结构。

        类的连接又分为验证、准备、解析三个阶段。验证是为了保证加载进来的字节流符合JVM的规范,不会对JVM造成安全性问题。其中包括对元数据的验证,例如检查类是否继承了被final修饰的类;还有对符号引用的验证,例如校验符号引用是否可以通过全限定名找到,或者是检查符号引用的权限(private、public)是否符合语法规定等。准备阶段是为类的类变量开辟空间并赋默认值。基本类型变量的默认值为0,引用类型默认值为null,常量默认值为声明值。解析是将Class在常量池中的符号引用转变为直接引用,此处针对的是静态方法及属性和私有方法与属性,因为这类方法与私有方法不能被重写,静态属性在运行期也没有多态这一说,即在编译器可知,运行期不可变,所以适合在该阶段解析。

        类的初始化为类的变量初始化值,有在声明类变量时,直接给变量赋值和在静态初始化块为类变量赋值两种方式。

九 对象在内存的中组成形式是什么

        对象在内存中存储的结构由三部分组成:对象头、实例数据、对齐填充。

        对象头分为markWord(标记字段)和class对象指针两部分,各占4字节;实例数据部分是真正存储的有效信息,大小为实际数据大小;对齐填充为可选部分,充当占位符。由于HotSpot VM的自动内存管理系统要求对象起始地址必须是8字节的整数倍,即对象的大小必须是8字节的整数倍。对象头正好是8字节的倍数(1倍或者2倍),因此当对象实例数据部分没有对齐的话,就需要通过对齐填充进行补全。

十 常见的jvm指令有哪些

1)jps :显示指定系统内所有的HotSpot虚拟机进程。

2)jstat:用于监视虚拟机运行时状态信息的命令,它可以显示出虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。

3)jinfo:用于实时查看和调整虚拟机各项参数。

4)jmap:用于生成heap dump文件。

5)jhat:与jmap搭配使用,用来分析jmap生成的dump,jhat内置了一个微型的HTTP/HTML服务器,生成dump的分析结果后,可以在浏览器中查看

6)jstack: 用于生成java虚拟机当前时刻的线程快照。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值