java面试题+jvm_java面试题:jvm

jvm内存区域

Q:jvm内存怎么划分的?

答:

方法区(线程共享):各个线程共享的一个区域,用于存储虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然 Java 虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却又一个别名叫做 Non-Heap(非堆),目的应该是与 Java 堆区分开来。

运行时常量池:是方法区的一部分,用于存放编译器生成的各种字面量和符号引用。

堆内存(线程共享):所有线程共享的一块区域,垃圾收集器管理的主要区域。主要存储对象、数组。

Java 堆中还可以细分为:新生代和老年代;再细致一点的有 Eden 空间、From Survivor 空间、To Survivor 空间等,默认情况下新生代按照8:1:1的比例来分配。

程序计数器: Java 线程私有,它可以看做是当前线程所执行的字节码的行号指示器。

虚拟机栈(栈内存):Java线程私有,虚拟机展描述的是Java方法执行的内存模型:每个方法在执行的时候,都会创建一个栈帧用于存储局部变量、操作数、动态链接、方法出口等信息;每个方法调用都意味着一个栈帧在虚拟机栈中入栈到出栈的过程;

本地方法栈 :和Java虚拟机栈的作用类似,区别是该区域为 jvm提供使用 native 方法的服务。

Q:成员变量,是在栈还是在堆里面?

类的成员变量都在堆上。

只有方法里面定义的基础变量、在方法里面定义的引用、其他对象的引用放在栈上

垃圾收集器

Q:垃圾回收器有哪些?

Java有四种类型的垃圾回收器:

串行垃圾回收器(Serial Garbage Collector)

并行垃圾回收器(Parallel Garbage Collector)

并发标记扫描垃圾回收器(CMS Garbage Collector)

G1垃圾回收器(G1 Garbage Collector)

Q:垃圾收集器有哪些?

垃圾收集器:Serial收集器、ParNew收集器、Parallel Scavenge收集器、Serial Old收集器、Parallel Old收集器、CMS收集器、G1收集器。

Jdk11推出了ZGC,号称可以达到10ms 以下的 GC 停顿,承诺在数TB的堆上具有非常低的暂停时间。

Q:这些垃圾收集器有什么不同,主要使用哪些垃圾收集算法 ?

Serial 垃圾收集器(单线程、复制算法), ParNew 垃圾收集器(Serial+多线程),Parallel Scavenge 收集器(多线程复制算法、高效),Serial Old 收集器(单线程标记整理算法 ),Parallel Old 收集器(多线程标记整理算法) ,CMS 收集器(多线程标记清除算法)。

G1 收集器两个最突出的改进是:

(1)基于标记-整理算法,不产生内存碎片。

(2)可以非常精确控制停顿时间,在不牺牲吞吐量前提下,实现低停顿垃圾回收。

垃圾收集算法

Q:垃圾收集算法有哪些?

标记-清除算法、复制算法、标记-整理算法、分代收集算法

Q:标记清除算法和标记整理算法,有什么区别?

标记清除算法:标记出所有需要回收的对象,然后回收被标记的对象所占用的空间。

标记清除算法缺点是:清除后内存碎片化严重,后续可能发生大对象不能找到可利用空间的问题。

标记整理算法:标记整理和标记清除算法很像,唯一不同的是,当标记完成后,不是清理掉需要回收的对象,而是将所有存活的对象向一端移动,然后将边界以外的内存全部清理掉,这样可以有效避免空间碎片的产生。

内存分配与回收策略

Q:内存分配有哪些规则?

答:

有新生代和老年代。新生代又分为 Eden区、ServivorFrom、ServivorTo三个区。

(1)新创建的对象优先分配在Eden区,如果Eden区没有足够的空间时,虚拟机执行一次Minor GC。

由于频繁创建对象,所以新生代会频繁触发MinorGC 进行垃圾回收。

(2)大对象直接进入老年代(大对象是指需要大量连续内存空间的对象)。这样做的目的是避免在Eden区和两个Survivor区之间发生大量的内存拷贝(新生代采用复制算法收集内存)。

(3)长期存活的对象进入老年代。虚拟机为每个对象定义了一个年龄计数器,如果对象经过了1次Minor GC那么对象会进入Survivor区,之后每经过一次Minor GC那么对象的年龄加1,知道达到阀值对象进入老年区。

(4)动态判断对象的年龄。如果Survivor区中相同年龄的所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象可以直接进入老年代。

(5)空间分配担保。每次进行Minor GC时,jvm会计算Survivor区移至老年区的对象的平均大小,如果这个值大于老年区的剩余值大小则进行一次Full GC,如果小于检查HandlePromotionFailure设置,如果true则只进行Minor GC,如果false则进行Full GC。

Q:MinorGC、MajorGC、FullGC的区别是什么?

Minor GC:简单理解就是发生在年轻代的GC。

Minor GC的触发条件为:

当产生一个新对象,新对象优先在Eden区分配。

如果Eden区放不下这个对象,虚拟机会使用复制算法发生一次Minor GC,清除掉无用对象,同时将存活对象移动到Survivor的其中一个区(fromspace区或者tospace区)。

如果新生对象在Eden区无法分配空间时,此时发生Minor GC。

发生MinorGC,对象会从Eden区进入Survivor区,如果Survivor区放不下从Eden区过来的对象时,此时会使用分配担保机制将对象直接移动到年老代。

Major GC的触发条件:Major GC又称为Full GC。当年老代空间不够用的时候,虚拟机会使用“标记—清除”或者“标记—整理”算法清理出连续的内存空间,分配对象使用。出现Major GC通常会出现至少一次Minor GC?

Q:年轻代,老年代,分别采用哪些垃圾回收算法?为什么要采用这些算法??

年轻代的垃圾回收是Minor GC,采用的垃圾回收算法是复制算法。因为新生代中每次垃圾回收都要回收大部分对象,只有少量存活对象存活,也就是说要复制的存活对象比较少。

老年代的垃圾回收是Full GC,采用的垃圾回收算法是标记--清除算法。老年代因为对象存活率高、没有额外空间对它进行分配担保, 就必须采用“标记—清理”或“标

记—整理”算法来进行回收, 不必进行内存复制, 且直接腾出空闲内存.

Q:讲一下MinorGC的过程。

MinorGC 采用复制算法。

MinorGC 的过程(复制->清空->互换)。

(1):eden、servicorFrom 复制到 ServicorTo,年龄+1。

首先,把 Eden 和 ServivorFrom 区域中存活的对象复制到 ServicorTo 区域(如果有对象的年龄以及达到了老年的标准,则赋值到老年代区),同时把这些对象的年龄+1(如果 ServicorTo 不够位置了就放到老年区);

(2):清空 eden、servicorFrom。

然后,清空 Eden 和 ServicorFrom 中的对象;

(3):ServicorTo 和 ServicorFrom 互换。

最后,ServicorTo 和 ServicorFrom 互换,原 ServicorTo 成为下一次 GC 时的 ServicorFrom区。

FullGC

Q:发生FullGC的原因有哪些?

Full GC的触发条件大致情况有以下几种情况:

程序执行了System.gc(); //建议jvm执行fullgc,并不一定会执行

执行了jmap -histo:live pid命令。 //这个会立即触发fullgc

在执行minor gc的时候进行的一系列检查:

a. 执行Minor GC的时候,JVM会检查老年代中最大连续可用空间是否大于了当前新生代所有对象的总大小。

b. 如果大于,则直接执行Minor GC(这个时候执行是没有风险的)。

c. 如果小于了,JVM会检查是否开启了空间分配担保机制,如果没有开启则直接改为执行Full GC。

d. 如果开启了,则JVM会检查老年代中最大连续可用空间是否大于了历次晋升到老年代中的平均大小,如果小于则执行改为执行Full GC。

如果大于则会执行Minor GC,如果Minor GC执行失败则会执行Full GC

使用了大对象。 //大对象会直接进入老年代

在程序中长期持有了对象的引用。 //对象年龄达到指定阈值也会进入老年代

Q:频繁发生FullGC,会有什么后果?

Stop The World。此时所有的用户线程都会暂停运行,会发生卡顿现象。

Q:如何分析频繁发生FullGC的原因,以及解决方案?

可以通过命令jmap -dump得到dump文件。

也可以设置jvm的参数-XX:+HeapDumpBeforeFullGC和 -XX:HeapDumpOnOutOfMemoryError ,自动生成dump文件。

然后对dump文件进行分析,看是哪些对象占用了太多的内存。

类的加载机制

Q:java 中都有哪些引用类型?

Q:ClassLoader类加载是发生在哪块内存区域?

答:将Java类的.class文件中的二进制数据读入到内存中,放置在运行时数据区的方法区内。(存疑)

Q:讲一下类加载的过程。

虚拟机类加载机制的生命周期:加载,验证,准备,解析,初始化,使用,卸载。

其中,验证,准备,解析这三个过程又称为“连接”。

Q:类的加载器ClassLoader有哪些?

JVM提供了3种类加载器: BootstrapClassLoader、 ExtClassLoader、 AppClassLoader分别加载Java核心类库、扩展类库以及应用的类路径( CLASSPATH)下的类库。

Q:类的加载机制是怎样的?

双亲委派机制。

当一个类加载器收到类加载任务时,会先交给自己的父加载器去完成,因此最终加载任务都会传递到最顶层的BootstrapClassLoader,只有当父加载器无法完成加载任务时,才会尝试自己来加载。

采用双亲委派模型的一个好处是保证使用不同类加载器最终得到的都是同一个对象,这样就可以保证Java 核心库的类型安全,比如,加载位于rt.jar包中的 java.lang.Object类,不管是哪个加载器加载这个类,最终都是委托给顶层的BootstrapClassLoader来加载的,这样就可以保证任何的类加载器最终得到的都是同样一个Object对象。

jvm调优

Q:jvm有哪些参数?

-XmsSize(最小堆内存)

-XmxSize(最大堆内存)

-XmnSize(分配给年轻代)

-XX:+PrintGCDetails 输出详细GC日志

-XX:SurvivorRatio=ratio Eden区和survivor区的比例

-XX:NewRatio=n:设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4

-XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5

-XX:-UseTLAB 是否使用本地线程分配缓冲

-XX:+HeapDumpOnOutOfMemoryError(在出现异常的情况下 将内存快照dump出来)

-XssSize 栈大小

-XX:MaxPermSize 方法区的最大值(JDK<=1.7 1.8将方法区移去,增加了metaspaces)

-XX:PermSize 方法区的大小

java内存模型

Q:java的内存模型是怎样的?

Java 虚拟机规范中试图定义一种 Java 内存模型(Java Memory Model, JMM)来屏蔽掉各层硬件和操作系统的内存访问差异,以实现让 Java 程序在各种平台下都能达到一致的内存访问效果。

Java 内存模型规定了所有的变量都存储在主内存(Main Memory)中。每条线程还有自己的工作内存(Working Memory),线程的工作内存中保存了被该线程使用到的变量的主内存副本拷贝,线程对变量的所有操作(读取、赋值等)都必须在主内存中进行,而不能直接读写主内存中的变量。不同的线程之间也无法直接访问对方工作内存中的变量,线程间的变量值的传递均需要通过主内存来完成

待补充.

参考资料:

《深入理解java虚拟机》

《深入理解java虚拟机》学习笔记

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值