JVM面试题

字节跳动:

1.JVM的组成

JVM:运行时数据区,类加载器,执行引擎,本地接口

在这里插入图片描述运行时数据区(JVM内存):
堆:对象实例
栈:局部变量表,方法出口
方法区:类信息,常量,静态变量,编译后的代码
程序计数器:行号指示器。循环,跳转等基础指令
本地方法栈:VM调用native方法
在这里插入图片描述
执行引擎: gc编译器
执行引擎是java虚拟机的最核心组件之一,它负责执行虚拟机的字节码,现代虚拟机为了提高执行效率,会使用即时编译技术将方法编译成机器码后再执行。

2.什么是类加载器,类加载器有哪些?

类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个这个类的Java.lang.Class对象,用来封装类在方法区类的对象。
启动类加载器(Bootstrap ClassLoader)
负责将JAVA_HOME;\lib目录下的类库加载到虚拟机内存中,用来加载java的核心库,此类加载器并不继承于java.lang.ClassLoader,不能被java程序直接调用,代码是使用C++编写的.是虚拟机自身的一部分.

扩展类加载器(Extendsion ClassLoader)
负责加载\lib\ext目录下的类库,用来加载java的扩展库,开发者可以直接使用这个类加载器.

应用程序类加载器(Application ClassLoader)
负责加载用户类路径(CLASSPATH)下的类库,一般我们编写的java类都是由这个类加载器加载,这个类加载器是CLassLoader中的getSystemClassLoader()方法的返回值,所以也称为系统类加载器.一般情况下这就是系统默认的类加载器.

3.Java的内存分区

方法区,本地方法区,虚拟机栈,堆,程序计数器

4.什么时候对象会进入老年代?

1.大对象直接进入老年代(-XX:PretenureSizeThreshold=3145728 3M,这个参数只在 Serial 和ParNew两个收集器下有效。)
2.长期存活的对象进入老年代(-XX:MaxTenuringThreshold=15)
3.动态对象年龄判定(虚拟机并不会永远地要求对象的年龄都必须达到MaxTenuringThreshold才能晋升老年代,如果Survivor空间中相同年龄的所有对象的大小总和大于Survivor的一半,年龄大于或等于该年龄的对象就可以直接进入老年代)

5.常见的垃圾回收器算法有哪些,各有什么优劣?

引用计数法
标记清除
复制
标记整理
分代收集算法

6.system,gc()和runtime,gc()会做什么事情?

这两个方法用来提示JVM要进行垃圾回收。但是,立即开始还是延迟进行垃圾回收是取决于JVM的。

java.lang.System.gc()只是java.lang.Runtime.getRuntime().gc()的简写,两者的行为没有任何不同。唯一要能说有什么不同那就是在字节码层面上调用前者比调用后者短一点点,前者是1条字节码而后者是2条

7.Java GC机制?GC Roots有哪些?

虚拟机栈(栈帧中的本地变量表)中引用的对象
方法区中类静态属性引用的对象
方法区中常量引用的对象
本地方法栈中 Java本地接口(即一般说的Native方法)引用的对象

8.CMS(Concurrent Mark Sweep)收集器特点,回收过程

CMS收集器是基于“标记—清除”算法实现的,CMS收集器的内存回收过程是与用户线程一起并发执行的,CMS仅作用于老年代,主要优点在名字上已经体现出来了:并发收集、低停顿

初始标记: 暂停所有的其他线程,并记录下直接与root相连的对象,速度很快 。
并发标记: 同时开启GC和⽤户线程,⽤⼀个闭包结构去记录可达对象。但在这个阶段结束,这个闭包结构并不能保证包含当前所有的可达对象。因为⽤户线程可能会不断的更新引⽤域,所以GC线程⽆法保证可达性分析的实时性。所以这个算法⾥会跟踪记录这些发⽣引⽤更新的地⽅。

重新标记: 重新标记阶段就是为了修正并发标记期间因为⽤户程序继续运⾏⽽导致标记产⽣变动的那⼀部分对象的标记记录,这个阶段的停顿时间⼀般会⽐初始标记阶段的时间稍⻓,远远⽐并发标记阶段时间短。

并发清除: 开启⽤户线程,同时GC线程开始对为标记的区域做清扫。

9.Java存在内存溢出的现象吗,内存的分配方式、GC机制;

1、基础数据类型直接在栈空间分配;
2、方法的形式参数,直接在栈空间分配,当方法调用完成后从栈空间回收;
3、引用数据类型,需要用 new 来创建,既在栈空间分配一个地址空间,又在堆空间分配对象的类变量;
4、方法的引用参数,在栈空间分配一个地址空间,并指向堆空间的对象区,当方法调用完后从栈空间回收;
5、局部变量 new 出来时,在栈空间和堆空间中分配空间,当局部变量生命周期结后,栈空间立刻被回收,堆空间区域等待 GC 回收;
6、方法调用时传入的实际参数,先在栈空间分配,在方法调用完成后从栈空间释放;
7、字符串常量在 DATA 区域分配 ,this 在堆空间分配;
8、数组既在栈空间分配数组名称, 又在堆空间分配数组实际的大小!

10.内存泄漏与内存溢出的区别

https://blog.csdn.net/u014401141/article/details/120135330

11.JVM的内存布局以及垃圾回收原理及过程讲一下,讲一下CMS垃圾收集器垃圾回收的流程,以及CMS的缺点

12.JVM如何调优、参数怎么调?

蚂蚁金服:

13.双亲委派机制及使用原因

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

采用双亲委派的一个好处是比如加载位于rt.jar包中的类java.lang.Object,不管是哪个加载器加载这个类,最终都是委托给顶层的启动类加载器进行加载,这样就保证了使用不同的类加载器最终得到的都是同样一个Object对象。双亲委派原则归纳一下就是:

可以避免重复加载,父类已经加载了,子类就不需要再次加载更加安全,很好的解决了各个类加载器的基础类的统一问题,如果不使用该种方式,那么用户可以随意定义类加载器来加载核心api,会带来相关隐患。
沙箱安全机制:自己写的java.lang.String.class类不会被加载,这样便可以防止核心 API库被随意篡改
避免类的重复加载:当父亲已经加载了该类时,就没有必要子ClassLoader再加载一 次,保证被加载类的唯一性

14.Java虚拟机内存模型能说说吗?Java8的内存分代改进?

15.对象在堆内存创建的生命周期

我是一个普通的java对象,我出生在Eden区,在Eden区我还看到和我长的很像的小兄弟,我们在Eden区中玩了挺长时间。有一天Eden区中的人实在是太多了,我就被迫去了Survivor区的“From”区,自从去了Survivor区,我就开始漂了,有时候在Survivor的“From”区,有时候在Survivor的“To”区,居无定所。直到我18岁的时候,爸爸说我成人了,该去社会上闯闯了。于是我就去了年老代那边,年老代里,人很多,并且年龄都挺大的,我在这里也认识了很多人。在年老代里,我生活了20年(每次GC加一岁),然后被回收。
在这里插入图片描述

16.JVM内存分布/内存结构?栈和堆的区别?堆的结构?为什么两个survivor区?

设置两个Survivor区最大的好处就是解决了碎片化

17.java对象头里有什么

对象组成分为3个区域:对象头、实例数据、对齐填充。
在这里插入图片描述
对象在内存中存储的结构由三部分组成:对象头、实例数据、对齐填充。

对象头

MarkWord(标记字段) :哈希码、分代年龄、锁标志位、偏向线程ID、偏向时间戳等信息。Mark Word被设计成了一个非固定的数据结构以便在极小的空间内存储尽量多的信息,它会根据对象的状态复用自己的存储空间。例外:如果是数组的话,还需要有一块区域存放数组大小,因为没办法从元数据确认数组大小,所以要存储到对象头的MarkWord中。

MarkWord是根据对象的状态区分不同的状态位,从而区分不同的存储结构。例如下图:
在这里插入图片描述
在这里插入图片描述

对象头的另一部分是类型指针(Klass Pointer)。

Klass Pointer(类型指针): 即指向当前对象的类的元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。并不是所有的虚拟机实现都必须在对象数据上保留类型指针,换句话说查找对象的元数据信息并不一定要经过对象本身。

另外,如果是数组,对象头中还有一块用于存放数组长度的数据,因为虚拟机可以通过普通Java对象的元数据信息确定Java对象的大小,但是从数组的元数据中无法确定数组的大小。 其中偏向锁和轻量级锁是java6以后对synchronized进行优化后新增的,稍后做介绍。

实例数据

实例数据部分是对象真正存储的有效信息,也就是我们在程序代码里面所定义的各种类型的字段内容,无论是从父类继承下来的,还是在子类中定义的都需要记录下来。 这部分的存储顺序会受到虚拟机分配策略参数(FieldsAllocationStyle)和字段在Java源码中定义顺序的影响。

HotSpot虚拟机 默认的分配策略为longs/doubles、ints、shorts/chars、bytes/booleans、oops(Ordinary Object Pointers),从分配策略中可以看出,相同宽度的字段总是被分配到一起。在满足这个前提条件的情况下,在父类中定义的变量会出现在子类之前。如果 CompactFields参数值为true(默认为true),那子类之中较窄的变量也可能会插入到父类变量的空隙之中。

对齐填充

第三部分对齐填充并不是必然存在的,也没有特别的含义,它仅仅起着占位符的作用。由于HotSpot VM的自动内存管理系统要求对象起始地址必须是8字节的整数倍,换句话说就是对象的大小必须是8字节的整数倍。对象头正好是8字节的倍数(1倍或者2倍),因此当对象实例数据部分没有对齐的话,就需要通过对齐填充来补全。

18.Eden和Survior的比例分配

Eden区和Survivor区的比例是8:1:1

19.JVM的内存划分,垃圾回收机制等

20.JVM的一次完整的GC流程(从ygc到fgc)是怎样的,重点讲讲对象如何晋升到老年代,几种主要的jvm参

MinorGC的过程:
MinorGC采用复制算法。当Eden区满时,首先,把Eden和ServivorFrom区域中存活的对象复制到ServicorTo区域(如果有对象的年龄以及达到了老年的标准,则赋值到老年代区),同时把这些对象的年龄+1(如ServicorTo不够位置了就放到老年区);然后,清空Eden,ServicorFrom中的对象,最后,ServicorTo和ServicorFrom互换,原ServicorTo成为下一次GC时的ServicorFrom区

新生代晋升老年代(对象内存分配和回收策略)
大对象直接进入老年代
长期存活的对象进入老年代
老年代的对象比较稳定,所以MajorGC(full GC)不会频繁执行。在进行MajorGC前一般都先进行了一次MinorGC,使得有新生代的对象晋身入老年代,导致空间不够用时才触发。当无法找到足够大的连续空间分配给新创建的较大对象时也会提前触发一次MajorGC进行垃圾回收腾出空间。
动态对象年龄判定(虚拟机并不会永远地要求对象的年龄都必须达到MaxTenuringThreshold才能晋升老年代,如果Survivor空间中相同年龄的所有对象的大小总和大于Survivor的一半,年龄大于或等于该年龄的对象就可以直接进入老年代)

MajorGC
MajorGC采用标记—清除算法:首先扫描一次所有老年代,标记出存活的对象,然后回收没有标记的对象。
当老年代也满了装不下的时候,就会抛出OOM(Out of Memory)异常。

Minor GC触发机制:
当年轻代满时就会触发Minor GC,这里的年轻代满指的是Eden代满,Survivor满不会引发GC。

Full GC触发机制:
(1)调用System.gc时,系统建议执行Full GC,但是不必然执行
(2)老年代空间不足
(3)方法区空间不足
(4)通过Minor GC后进入老年代的平均大小大于老年代的可用内存
(5)由Eden区、survivor space1(From Space)区向survivor space2(To Space)区复制时,对象大小大于To Space可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小
当永久代满时也会引发Full GC,会导致Class、Method元信息的卸载

21.OOM的错误,StackOverFlow错误,permgen space的错误StackOverFlowError错误?

StackOverFlow错误
栈溢出错误。当一个应用调用递归没有结束判断或者递归太深时会导致堆栈溢出或陷入死循环时抛出该错误。
出现的情况:递归,还有就是当两个对象A包含B,B包含A,然后序列化时也会出现这个错误。
解决: 注意递归的使用,和序列化类的编写。

PermGen space的全称是Permanent Generation space,是指内存的永久保存区域,这块内存主要是被JVM存放Class和Meta信息的,Class在被Loader时就会被放到PermGen space中,它和存放类实例(Instance)的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对PermGen space进行清理,所以如果你的应用中有很多CLASS的话,就很可能出现PermGen space错误,这种错误常见在web服务器对JSP进行pre compile的时候。如果你的WEB APP下都用了大量的第三方jar, 其大小超过了jvm默认的大小(4M)那么就会产生此错误信息了。
解决方法:
手动设置MaxPermSize大小,如果是linux系统,修改TOMCAT_HOME/bin/catalina.sh,如果是windows系统,修改TOMCAT_HOME/bin/catalina.bat,
在“echo “Using CATALINA_BASE: $CATALINA_BASE””上面加入以下行:
JAVA_OPTS="-server -XX:PermSize=64M -XX:MaxPermSize=128m
建议:将相同的第三方jar文件移置到tomcat/shared/lib目录下,这样可以达到减少jar 文档重复占用内存的目的。

22.你知道哪几种垃圾回收器,各自的优缺点,重点讲一下cms和g1

23.G1回收器讲下回收过程

24.什么时候对象可以被收回?

GC Roots通过一系列的名为GC Roots的对象作为起始点,从这些节点开始向下搜索,搜索过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时,则证明对象是不可用的。

在Java中,可以作为GC Roots的对象包括下面几种:

虚拟机栈中引用的对象;
方法区中类静态属性引用的对象;
方法区中的常量引用的对象;
本地方法栈中JNI(即一般说的Native方法)的引用的对象;

小结

总的来说就是当一个对象通过GC Roots搜索不到时,说明对象可以被回收了,但什么时候回收还要看GC的心情!

25.JVM诊断调优工具用过哪些?

https://www.processon.com/mindmap/5c13c180e4b06db7dfdd7897

26.jvm调优 - 堆空间各区域大小如何划分配置?

堆空间各区域大小划分

在调优之前,我们首先要知道目前项目中长期存活的对象占用了多大的内存空间,也就是老年代的空间有多少活跃数据,这个数据可以通过查看GC日志得到,就是每次fullgc后老年代还有多少空间,因为每次的值都不一样,所以我们可以取一个平均值;得到这个平均值后,就可以设置堆空间区域大小了,下图是一个参考标准,接下来我们就以这参考图来设置各空间的大小
在这里插入图片描述
比如我项目中老年代活跃数据的大小为500M,在这里我们都取一个最大值,那么我们就可以这样设置

总大小:设置堆空间总大小公式为: 500*4=2000M,将堆内存最大和初始内存都设为2000,jvm参数为:-Xmx2000m -Xms2000m
新生代:设置堆空间的新生代大小公式为:500*1=500M,jvm参数为:-XX:NewSize=500m -XX:MaxNewSize=500m
老年代:设置堆空间的老年代大小公式为:500*3=1500:因为老年代只能设置比例,所以我们设置新生代和老年代的比例为1:3,jvm参数为:-XX:NewRatio=3,这样经过换算下来,老年代就有 1500M 的空间了
永久代/元空间 :注意这里取值必须是full gc 后的永久代空间,比如经过GC清理后,我的永久代活跃数据为100m,那我们就设置为150M;jvm参数为:-XX: PermSize=150m --XX: PermSize=150m

https://blog.csdn.net/u014401141/article/details/121908219

27.JVM相关的分析工具使用过的有哪些?具体的性能调优步骤?

命令行:
jps查看java进程
jinfo实时查看和调整JVM配置参数
jstat查看虚拟机性能统计信息
jmap生成堆转储快照
jhat:堆转储快照分析工具
jstack:Java堆栈跟踪工具

可视化故障处理工具:
JConsole:一款基于JMX(Java Manage-ment Extensions)的可视化监视、管理工具
Java VisualVM:
它除了常规的运行监视、故障处理外,还将提供其他方面的能力,譬如性能分析(Profiling)
MAT:Java堆分析器,用于查找内存泄漏
GC日志分析工具 : https://gceasy.io
ArtThas-阿里巴巴实时JVM调优工具

28.常用的JVM的参数

https://render.alipay.com/p/s/jvm-generate/JvmParams
在这里插入图片描述

小米:

有做过JVM内存优化吗?
从SQL、JVM、架构、数据库四个方面讲讲优化思路
双亲委派模型介绍一下
jvm内存分区,为什么要有新生代和老年代
说几个垃圾回收器,cms回收器有哪几个过程,停顿几次,会不会产生内存碎片。老年代产生内存碎片会有什么问题。
jvm场景问题, 标记清除多次后老年代产生内存碎片,引起full gc,接下来可能发生什么问题。

滴滴:

一面:说一下什么情况发生栈溢出
一面:java的垃圾回收器都有哪些,说下g1的应用场景,平时你是如何搭配使用垃圾回收器的
二面;有实际的JVM性能调优案例吗?重点需要关注哪些核心参数?
JVM类加载机制
一面:讲一下双亲委派模型,以及其优点
一面:讲一下JVM内存布局

美团:

Java类加载过程

描述一下jvm加载class文件的原理机制

京东:

什么是类的加载?
哪些情况会触发类的加载?
讲一下JVM加载一个类的过程
JVM的类加载机制是什么?
类加载器的双亲委派模型是什么?
双亲委派机制可以打破吗?为什么

此外:
简单说说你了解的类加载器
JVM的内存结构,Eden和Survivor比例。
JVM内存为什么要分成新生代,老年代,持久代。新生代中为什么要分为Eden和Survivor。

JVM中一次完整的GC流程是怎样的,对象如何晋升到老年代,说说你知道的几种主要的JVM参数。
你知道哪几种垃圾收集器,各自的优缺点,重点讲下cms和G1,包括原理,流程,优缺点。
垃圾回收算法的实现原理。
当出现了内存溢出,你怎么排错。
一面:Java GC机制?GC Roots有哪些?
一面:Java怎么进行垃圾回收的?什么对象会进老年代?垃圾回收算法有哪些?为什么新生代使用复制算法?
JVM垃圾收集算法与收集器有哪些?
讲一下Jvm中如何判断对象的生死?

JVM诊断调优工具用过哪些?
每秒几十万并发的秒杀系统为什么会频繁发生GC?
日均百万级交易系统如何优化JVM?
线上生产系统OOM如何监控及定位与解决?
高并发系统如何基于G1垃圾回收器优化性能?

携程:

讲讲jvm分区
讲讲jvm的gc

天猫:

一面:Jvm内存模型以及分区,需要详细到每个区放什么。
一面:JVM的内存模型,Java8做了什么修改

拼多多:

JVM 内存分哪几个区,每个区的作用是什么?
JVM有哪些回收算法,对应的收集器有哪些?
GC 的两种判定方法 ?CMS 收集器与 G1 收集器的特点。
Java GC机制?GC Roots有哪些?
从SQL、JVM、架构、数据库四个方面讲讲优化思路

美团:

java内存分配
jvm的永久代中会发生垃圾回收吗?
一面:jvm内存分区,为什么要有新生代和老年代?

阿里:

说一说Java内存区域。
Java虚拟机中,数据类型可以分为哪几类?
怎么理解栈、堆?堆中存什么?栈中存什么?
为什么要把堆和栈区分出来呢?栈中不是也可以存储数据吗?
在Java中,什么是栈的起始点,同是也是程序的起始点?
为什么不把基本类型放堆中呢?
Java中的参数传递时传值呢?还是传引用?
Java中有没有指针的概念?
Java中,栈的大小通过什么参数来设置?
堆大小通过什么参数设置?

此外:
什么情况下会发生栈内存溢出。
JVM的内存结构,Eden和Survivor比例。
JVM内存为什么要分成新生代,老年代,持久代。新生代中为什么要分为Eden和Survivor。
讲一讲垃圾回收算法。
如何解决内存碎片的问题?
什么情况下触发垃圾回收?
如何选择合适的垃圾收集算法?
JVM有哪三种垃圾回收器?
JVM中最大堆大小有没有限制?
吞吐量优先选择什么垃圾回收器?响应时间优先呢?
如何进行JVM调优?有哪些方法?
如何理解内存泄漏问题?有哪些情况会导致内存泄露?如何解决?

天猫:

一面:jvm GC原理,JVM怎么回收内存
一面:CMS特点,垃圾回收算法有哪些?各自的优缺点,他们共同的缺点是什么?

腾讯:

jvm怎样 判断一个对象是否可回收,怎样的对象才能作为GC root
OOM说一下?怎么排查?哪些会导致OOM? OOM出现在什么时候
什么是Full GC?GC? major GC? stop the world
描述JVM中一次full gc过程

美团:

GC是什么?为什么要有GC?
简述java垃圾回收机制
如何判断一个对象是否存活?(或者GC对象的判定方法)
垃圾回收的优点和原理。并考虑2种回收机制。
垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?
有什么办法主动通知虚拟机进行垃圾回收?
java中会存在内存泄漏吗,请简单描述。
二面:jvm场景问题, 标记清除多次后老年代产生内存碎片,引起full gc,接下来可能发生什么问题?
GC root如何确定,哪些对象可以作为GC Root?
GC如何分代的?各代用什么算法回收?
CMS过程是怎样的?内部使用什么算法做垃圾回收?
分代垃圾回收过程?

此外:
JVM中一次完整的GC流程是怎样的,对象如何晋升到老年代,说说你知道的几种主要的JVM参数。
你知道哪几种垃圾收集器,各自的优缺点,重点讲下cms和G1,包括原理,流程,优缺点。
垃圾回收算法的实现原理。
当出现了内存溢出,你怎么排错。
g1和cms区别,吞吐量优先和响应优先的垃圾收集器选择
串行(serial)收集器和吞吐量(throughout)收集器的区别是什么?
在Java中,对象什么时候可以被垃圾回收?
简述Java内存分配与回收策率以及minor GC和majorGC。
Java中垃圾收集的方法有哪些?

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值