面试汇总——JavaSE——JVM

看各种博客整理以及自己总结的

JVM

JVM
请简单描述一下JVM加载class文件的原理是什么?

字节码文件是保存在硬盘上的,通过类加载子系统,或将其加载到内存中,最终实例化成多个一模一样的实例

JVM虚拟机通过双亲委派机制来加载字节码文件,在类加载子系统中一般会经过

  1. 加载【~~通过全限定名获取此类的二进制流,~~在内存中生成一个代表这个类的Class对象】,
  2. 链接(验证【验证释放符合Java虚拟机的规范】,准备【对静态变量进行默认初始化】,解析【将符合引用变为直接引用】),
  3. 初始化【执行类构造器方法()的过程】三个阶段
什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”?

Java虚拟机是用来运行字节码文件的虚拟机进程,因为只要符合虚拟机额规范的任何字节码文件都可以在Java虚拟机上运行

jvm最大内存限制多少?

Xms:1/64,Xmx:1/4当堆的空余内存小于40%时,会一直增大到最大内存;当空余内存小于70%,会一直减小到最小内存

jvm是如何实现线程的?
  1. 使用内核线程:由操作系统内核支持的线程称为内核线程,内核通过操作调度器将线程上的任务映射到各个处理器上,但是由于系统调用线程,会在用户态和内核态之间来回切换,会导致效率受限制
  2. 使用用户线程:用户线程完全建立在用户空间的线程库之上,不需要切换成内核态,且效率高消耗少,但正是因为没有内核的支持,处理一些例如阻塞的问题非常困难
  3. 使用用户线程加轻量级进程混合:可以使用内核提供的调度器和处理映射器,同时由于用户线程的系统调度通过轻量级进程完成,大大降低了阻塞的风险
请说明一下eden区和survial区的含义以及工作原理?

Eden区:是为新创建的对象分配内存的

Survivor区:分为Survivor from和Survivor to,用来存放每次幸存的对象

当Eden区满时会进行一次Minor GC,会先扫描Eden和Survivor0,将存活的对象放到Survivor1,同时将在Survivor0中存活的对你年龄+1,再接着扫描Eden和Survivor1,同时将在Survivor1中存活的对象年龄+1,此时再将存活的对象放入Survivor0…【直到年龄到达(默认)15时进入年老区】这样做是为了减少内存中的碎片,当经过多次扫描在仍然在Survivor中存活的对象放到老年代(老年代里存放的一般是大对象和常用的对象)

年轻代采用复制算法,年老代采用标记-清理算法

Ende:Survivor from:Survivor to=8:1:1

对于年轻代的回收称为Minor GC,对于老年代的回收称为Major GC,对于整个堆的回收称为Full GC

请简单描述一下JVM分区都有哪些?

JVM分区就是我们一般所说的运行时数据区

  1. 堆:是虚拟机中内存最大的区域,主要用来存放创建的对象
  2. 方法区
  3. 本地方法栈
    1. 局部变量表
    2. 操作数栈
    3. 动态链接
    4. 方法返回值
    5. 一些附加信息
  4. Java虚拟机栈
  5. 程序计数器:用来记录下一条指令的地址
请简单描述一下类的加载过程

字节码文件在类加载器子系统中,主要经过

  1. 加载
    1. 将源文件编译成字节码文件的过程中,生成一个Class对象
  2. 链接
    1. 验证:看字节码文件是否符合JVM的规范
    2. 准备:给static(静态)变量分配内存空间并赋默认的初始值,给static final赋真实的值
    3. 解析:将符合引用转换为直接引用
  3. 初始化
    1. 执行类构造器方法(),【存在static变量时才会有此方法】,()是由编译器自动收集类中的类变量的赋值操作以及静态语句块中的语句合并而成的,JVM在执行()之前,会先加载父类的()
请简单说明一下JVM的回收算法以及它的回收器是什么?还有CMS采用哪种回收算法?使用CMS怎样解决内存碎片的问题呢?

垃圾回收算法

  1. 标记-清理算法

    此算法主要针对老年区,由于老年区都是大对象和一些经常用的对象,所以采用标记-清理算法,可以有效的清理不用的对象,标记所以从根节点开始的对象,如果是未被标记的对象,即没有引用的对象,可以将其清理掉,但是此方法会产生较多的内存碎片

  2. 复制算法

    此方法主要用在年轻代,由于年轻代中的大部分对象都是需要被清理掉的,因此采用复制算法,可以方便的将存活的对象进行保存,此方法主要是在垃圾收集时将Eden区和Survivor区中存活的对象放入另一个Survivor区,依次类推,可以将不用的对象全部清理掉

  3. 标记整理算法

    标记整理算法是基于标记-清理算法,是此算法的一种优化,由于标记-清理算法会产生较多的内存碎片,因此产生了标记整理算法,标记整理算法也是从根节点开始标记,将标记(存活)的对象压缩在内存的一端,之后清理边界外的所以对象,此算法可以有效的减少内存的碎片

  4. 增量算法

    如果进行一次垃圾清理是非常耗时的,此时会有长时间的停顿,所以将连接起来线程和用户线程交替进行,让垃圾收集线程每次回收一小片的内存区域,可以有效的减少停顿,并且在此期间用户线程也可以运行,但是由于线程之间的来回切换的消耗,导致垃圾回收的总体成本增加

垃圾回收器

串行垃圾收集器:单线程收集的唯一选择,它的单线程意义不仅仅是只使用一个CPU和一个收集线程,并且在收集线程运行期间,其他所有的线程都要停止工作(STW),适用于Client模式下和单核CPU的环境

  1. Serial(采用复制算法):用于年轻代,没有线程交换的开销,可以专注的做收集工作,可以提高工作的运行效率
  2. Serial Old(采用标记-清理算法):用于老年代。在Server模式下,JDK1.5之前主要是与Parallel Scanvenge收集器搭配使用,另外一个就是作为CMS收集器的后备预案,在并发收集发生Concurrent Mode Failure的时候使用。

通过指定-UseSerialGC参数,使用Serial + Serial Old的串行收集器组合进行内存回收。

并行垃圾收集器:并行垃圾收集器相对于串行垃圾收集器,是通过多线程实现的,但是也是STW,适合Server模式和多核CPU的环境下

  1. ParNew:是Serial的多线程版本,在运行时也是STW,但是会开启多个线程进行回收(默认开启的收集线程和CPU的数量一样),-UseParNewGC: 打开此开关后,使用ParNew + Serial Old的收集器组合进行内存回收,这样新生代使用并行收集器,老年代使用串行收集器。
  2. Parallel Scavenge:采用复制算法,主要关注吞吐量【(运行用户代码的时间/运行用户代码的时间+)垃圾收集的时间】,而高的吞吐量可以提高CPU的运行效率
  3. Parllel Old:是Parallel Scavenge的老年代的收集版本,因为之前对于老年代一直是单线程的Serial Old,运行效率低,即使使用Parallel Scavenge整体效率也不会有太多的提升,因此在注重cpu效率的场合可以使用Parallel Scavenge+ Parllel Old

-UseParallelGC: 虚拟机运行在Server模式下的默认值,打开此开关后,使用Parallel Scavenge + Serial Old的收集器组合进行内存回收。-UseParallelOldGC: 打开此开关后,使用Parallel Scavenge + Parallel Old的收集器组合进行垃圾回收

CMS采用的回收算法

CMS收集器是一种很重要的收集器以获取最短收集停顿时间为目标的收集器,是基于标记清除算法的,其主要步骤:初始标记,并发标记,重新标记,并发清除,其中初始标记和重新标记还会STW,但是并发标记个并发清除会和用户线程一起运行

触发原因:当gc线程和用户线程同时运行的时候,此时用户线程产生的垃圾大于预留的空间,此时会触发CMS(Concurrent Model sweep)

使用CMS解决碎片问题

解决这个问题的办法就是可以让CMS在进行一定次数的Full GC(标记清除)的时候进行一次标记整理算法,CMS提供了以下参数来控制:

-XX:UseCMSCompactAtFullCollection -XX:CMSFullGCBeforeCompaction=5

也就是CMS在进行5次Full GC(标记清除)之后进行一次标记整理算法,从而可以控制老年带的碎片在一定的数量以内,甚至可以配置CMS在每次Full GC的时候都进行内存的整理。

JVM内存模型
请问什么是JVM内存模型?

可以理解为运行时数据区

  1. 堆:是Java虚拟机中内存最大的区域,是所有线程共享的,我们可以通过设置-Xms和-Xmx来设置其堆的起始(最小)内存,以及最大内存,最小内存默认是物理内存的1/64最大内存默认是物理内存的1/4,当空余的堆内存小于40%,此时内存会一直增大到最大内存,当空余堆大于70%时,此时内存会一直减少到最小内存,在堆中,有新生代【Eden+Survivor0+Survivor1其比例为8:1:1】+年老代+持久代
  2. 方法区:也称为永久代,用来存放虚拟机加载的类信息,静态方法,常量,是线程共享的,默认最小值是16MB,默认最大值是64MB,可以通过-XX:permSize和-XX:MaxPermSize来设置参数,是一片连续的堆空间,永久代的垃圾收集和老年代是捆绑在一起的,因为不论谁满了,都会触发永久代和老年代的垃圾收集
  3. 本地方法栈:为Native方法服务的
  4. Java虚拟机栈:Java虚拟机栈是由一个个栈帧组成的,栈帧可以理解成一个个方法,栈帧是由局部变量表、操作数栈、动态链接、方法出口,以及一些附加信息组成,是线程私有的,每一个方法的调用和销毁都对应着一个栈帧的入栈和出栈。局部变量表中double和long类型占会占用两个空间,而其他基本类型只会占用一个空间,局部变量表的大小在编译时期就会确定,在运行期间其大小不会发生变化
  5. 程序计数器:是最小的一块内存区,用来记录所要执行的下一个字节码指令的地址
  6. 【(不是Java虚拟机内存的一部分)直接内存,在JDK1.4中加入了NIO可以,引入了通道与缓冲区的IO方式,可以调用Native方法,直接分配堆外内存,这个堆外内存就是本机内存,不会影响堆内存的大小】
JAVA虚拟机
请列举一下,在JAVA虚拟机中,哪些对象可作为ROOT对象?

虚拟机栈中的引用对象

方法区中常量的引用对象

方法区中类静态变量的引用对象

本地方法栈中JNI的引用对象

GC中如何判断对象是否需要被回收?

首先会判对此对象有没有引用或与其他引用有关联,如果没有则会被回收,如果有引用则不会被回收,但是这种方法无法识别循环引用,因此此时就用到了可达性分析,是指从此对象到Roots看有没有引用链,没有引用链的对象不会立即被回收,还要经过至少两次的标记,如果在此期间没有逃脱回收对象,那么很大程度会被回收的,能够被回收主要看finalize()有没有与引用链关联,如果有关联则自救成功,如果没有成功被二次标记,就可以称为回收对象了

请说明一下JAVA虚拟机的作用是什么?

运行字节码文件,实现跨语言的平台,可以一次编译多次运行

如有不对的地方欢迎指出,共同进步!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值