Java面试题(一)Jvm


一、内存

提示:关于jvm的面试题,这里有20多道,基本涉及常问的笔试、面试部分,更多请关注微信公众号jdk1864。


1、内存模型以及分区

内存区主要分为两类:私有内存区和线程共享内存区。方法区和堆是所有线程共享的内存区域;而java栈、本地方法栈和程序员计数器是运行是线程私有的内存区域。

  1. Java堆(Heap),是Java虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。
  2. 方法区(Method Area),方法区与Java堆一样,是各个线程共享的内存区域,主要是存储类信息,常量池(static 常量和 static 变量),编译后的代码(字节码)等数据。
  3. 程序计数器(Program Counter Register),记录当前线程执行的行号。
  4. JVM栈(JVM Stacks),也叫虚拟机栈,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(StackFrame)用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
  5. 本地方法栈(Native Method Stacks),本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native方法服务。

2、堆区(Heap)里的分区:

堆区包含:新生代(Eden+Survivor 区,survivor 区里面分为 from 和 to 区)和老年代。
  1. 对象优先分配在Eden区,如果Eden区没有足够的空间时,虚拟机执行一次Minor GC。MGC 也叫 YGC
  2. 大对象直接进入老年代(大对象是指需要大量连续内存空间的对象)。这样做的目的是避免在Eden区和两个Survivor区之间发生大量的内存拷贝(新生代采用复制算法收集内存)。
  3. 长期存活的对象进入老年代。虚拟机为每个对象定义了一个年龄计数器,如果对象经过了1次Minor GC那么对象会进入Survivor区,之后每经过一次Minor GC那么对象的年龄加1,知道达到阀值对象进入老年区。
  4. 动态判断对象的年龄。如果Survivor区中相同年龄的所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象可以直接进入老年代。
  5. 空间分配担保。每次进行Minor GC时,JVM会计算Survivor区移至老年区的对象的平均大小,如果这个值大于老年区的剩余值大小则进行一次Full GC,如果小于检查HandlePromotionFailure设置,如果true则只进行Monitor GC,如果false则进行Full GC。

3、简述 java 内存分配与回收策率以及 Minor GC 和Major GC

  1. 对象优先在堆的 Eden 区分配。
  2. 大对象直接进入老年代.
  3. 长期存活的对象将直接进入老年代.
  4. 当 Eden 区没有足够的空间进行分配时,虚拟机会执行一次 Minor GC.Minor Gc 通常发生在新生代的 Eden 区,在这个区的对象生存期短,往往发生 Gc 的频率较高, 回收速度比较快;Full Gc / Major GC 发生在老年代,一般情况下,触发老年代 GC 的时候不会触发 Minor GC,但是通过配置,可以在 Full GC 之前进行一次 Minor GC 这样可以加快老年代的回收速度。

4、对象创建方法:

  1. 使用new关键字
  2. 使用Class类的newInstance方法,比如:
    Employee emp2 = (Employee) Class.forName("org.mitra.Employee").newInstance();
    
    Employee emp2 = Employee.class.newInstance();
    
  3. 使用Constructor类的newInstance方法
    Constructor<Employee> constructor = Employee.class.getConstructor();
    
    Employee emp3 = constructor.newInstance();
    
  4. 使用clone方法
    Employee emp4 = (Employee) emp3.clone();
    
  5. 使用反序列化
    为了反序列化一个对象,我们需要让我们的类实现Serializable接口。
    ObjectInputStream in = new ObjectInputStream(new FileInputStream("data.obj")); 
    Employee emp5 = (Employee) in.readObject();
    

5、GC 的两种判定方法:

  1. 引用计数法:指的是如果某个地方引用了这个对象就+1,如果失效了就-1,当为 0 就会回收但是 JVM 没有用这种方式,因为无法判定相互循环引用(A 引用 B,B 引用 A) 的情况。
  2. 引用链法(可达性算法): 通过一种 GC ROOT 的对象(方法区中静态变量引用的对象等-static 变量)来判断,如果有一条链能够到达 GC ROOT 就说明,不能到达 GC ROOT 就说明可以回收。

6、简述 java 垃圾回收机制:

  1. 在 java 中,程序员是不需要显示的去释放一个对象的内存的,而是由虚拟机自行执行。在JVM 中,有一个垃圾回收线程,它是低优先级的,在正常情况下是不会执行的,只有在虚拟机空闲或者当前堆内存不足时,才会触发执行,扫面那些没有被任何引用的对象,并将它们添加到要回收的集合中,进行回收。

7、垃圾收集算法:

GC最基础的算法有三种: 标记 -清除算法、复制算法、标记-压缩算法,我们常用的垃圾回收器一般都采用分代收集算法。

  1. 标记 -清除算法,“标记-清除”(Mark-Sweep)算法,如它的名字一样,算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收掉所有被标记的对象。
  2. 复制算法,“复制”(Copying)的收集算法,它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。
  3. 标记-压缩算法,标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存
  4. 分代收集算法,“分代收集”(Generational Collection)算法,把Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。

8、你知道哪些JVM性能调优:

  1. 设定堆内存大小。
    -Xmx:堆内存最大限制。-Xms:堆内存初始限制。-Xmn — 堆中年轻代的大小
  2. 设定新生代大小。 新生代不宜太小,否则会有大量对象涌入老年代。
    -XX:NewSize:新生代大小
    -XX:NewRatio 新生代和老生代占比
    -XX:SurvivorRatio:伊甸园空间和幸存者空间的占比

二、类加载

1、java的类加载:

  1. 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。
  2. 类的加载的最终产品是位于堆区中的Class对象,Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接口。

2、类加载过程(生命周期):

在这里插入图片描述

类的加载需要7个过程:

加载,查找并加载类的二进制数据,在Java堆中也创建一个java.lang.Class类的对象连接,连接又包含三块内容:验证、准备、初始化。

  1. 验证,文件格式、元数据、字节码、符号引用验证;
  2. 准备,为类的静态变量分配内存,并将其初始化为默认值;
  3. 解析,把类中的符号引用转换为直接引用

初始化,为类的静态变量赋予正确的初始值
使用,new出对象程序中使用
卸载,执行垃圾回收


3、类加载器双亲委派模型机制:

当一个类收到了类加载请求时,不会自己先去加载这个类,而是将其委派给父类,由父类去加载,如果此时父类不能加载,反馈给子类,由子类去完成类的加载。


4、什么是类加载器,类加载器有哪些:

实现通过类的权限定名获取该类的二进制字节流的代码块叫做类加载器。

主要有一下四种类加载器:

  1. 启动类加载器(Bootstrap ClassLoader)用来加载 java 核心类库,无法被 java 程序直接引用。

  2. 扩展类加载器(extensions class loader):它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。

  3. 系统类加载器(system class loader):它根据 Java 应用的类路径(CLASSPATH) 来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通过ClassLoader.getSystemClassLoader()来获取它。

  4. 用户自定义类加载器,通过继承 java.lang.ClassLoader 类的方式实现。

总结

这里对文章进行总结:
面试题最常问到的:
JVM三大性能调优参数,JVM 几个重要的参数
JVM调优
JVM内存管理,JVM的常见的垃圾收集器,G1垃圾收集器。GC调优,Minor GC ,Full GC 触发条件
java内存模型
Java垃圾回收机制
jvm怎样 判断一个对象是否可回收,怎样的对象才能作为GC root
OOM说一下?怎么排查?哪些会导致OOM? OOM出现在什么时候
什么是Full GC?GC? major GC? stop the world
描述JVM中一次full gc过程。
JVM中类加载机制,类加载过程,什么是双亲委派模型?,类加载器有哪些
如何判断是否有内存泄露?定位 Full GC 发生的原因,有哪些方式?
Java 中都有哪些引用类型?
有兴趣的可以关注公众号,我会不定期更新面试内容:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值