java面试之jvm基础问题

之前就准备总结一下常见的一些问题,可惜拖延症犯了,现在终于决定搞起来,先写第一篇,从jvm中常见的知识点说起来吧。

JVM

JVM通常情况下可以划分成五个区域:程序计数器,Java虚拟机栈,本地方法栈,堆,方法区(其中前三个区域各线程私有,相互独立,后面两个区域所有线程共享)。下边就是网上常见的内存区域划分图:
在这里插入图片描述
(这里的划分通常意义上是指HotSpot虚拟机,不同的虚拟机对内存区域的划分也不一样,同时同一个虚拟机不同版本也会有略微的区别,不过面试这么回答总是没有错的)

Java虚拟机栈

每当有java方法执行时,都会在虚拟机栈中创建一个栈帧,来存储局部变量表,操作数栈等,此区域会出现OOM等异常。

本地方法栈

类似于Java虚拟机栈,只不过运行的是Native方法。

程序计数器

程序计数器存储的是当前线程执行到的字节码的位置,当发生线程切换时,恢复线程就是从计数器里取出执行的位置。这块区域是不会发生OOM的。

Java堆

堆中存储了大部分的java对象实例和数组,是被所有线程共享的区域。也是发生垃圾回收的主要区域。

方法区

存储了被虚拟机加载的类型信息,常量,静态变量等数据,在JDK8以后,存储在方法区的元空间中(以前是存储在堆中的永久代中,JDK8以后已经没有永久代了)。

运行时常量池是方法区的一部分,会存储各种字面量和符号引用。具备动态性,运行时也可以添加新的常量入池(例如调用String的intern()方法时,如果常量池没有相应的字符串,会将它添加到常量池)(永久代,元空间这些也只针对于HotSpot虚拟机)

类加载

父类子类类加载顺序

这个基本上没有被问到过,但是还是需要知道,因为实际工作中可能会用到。
初始化父类的静态变量(如果是首次使用此类)

初始化子类的静态变量(如果是首次使用此类)

执行父类的静态代码块(如果是首次使用此类)

执行子类的静态代码块(如果是首次使用此类)

初始化父类的实例变量

初始化子类的实例变量

执行父类的普通代码块

执行子类的普通代码块

执行父类的构造器

执行子类的构造器

类加载的双亲委派机制

在这里插入图片描述
就是类加载器一共有三种:

启动类加载器:主要是在加载JAVA_HOME/lib目录下的特定名称jar包,例如rt.jar包,像java.lang就在这个jar包中。

扩展类加载器:主要是加载JAVA_HOME/lib/ext目录下的具备通用性的类库。

应用程序类加载器:加载用户类路径下所有的类库,也就是程序中默认的类加载器。
工作流程:

除启动类加载器以外,所有类加载器都有自己的父类加载器,类加载器收到一个类加载请求时,首先会判断类是否已经加载过了,没有的话会调用父类加载器的的loadClass方法,将请求委派为父加载器,当父类加载器无法完成类加载请求时,子加载器才尝试去加载这个类。 目的是为了保证每个类只加载一次,并且是由特定的类加载器进行加载(都是首先让启动类来进行加载)。

Java对象在内存中是如何存储的?

Java对象在内存中主要分为三部分:对象头、实例数据和对齐填充。
在这里插入图片描述
对象头:
对象头里主要包含对象自身的运行时数据(也就是图中Mark Word),类型指针(图中的Class Pointer,指向对象所属的类)。如果对象是数组,还需要包含数组长度(否则无法确定数组对象的大小)。
在这里插入图片描述
Mark Word:存储对象自身的运行时数据,例如hashCode,GC分代年龄,锁状态标志,线程持有的锁等等。在32位系统占4字节,在64位系统中占8字节。
Class Pointer:用来指向对象对应的Class对象(其对应的元数据对象)的内存地址。在开启了指针压缩时,占4字节。(默认是开启的)

Length:如果是数组对象,还有一个保存数组长度的空间,占4个字节。
实例数据:
保存的是对象的非静态成员变量数据,是真正的有效数据。
对齐填充:
因为HotSpot虚拟机的自动内存管理系统要求对象起始地址是8字节的整数倍,所以任何对象的大小必须是8字节的整数倍,而对象头部分一般是8字节的倍数,如果实例数据部分不是8字节的整数倍,需要对齐填充来补全。

垃圾回收

垃圾回收算法:
1.标记清除算法:会产生内存碎片且执行效率不稳定;常用于老年代
2.标记整理算法:移动过程需要STW,且整理时会改变对象的引用地址;常用于老年代
3.标记复制算法:无法100%利用内存空间,会造成一定的空间浪费。常用于新生代
4.分代回收算法:理论依据是分代假说,弱分代假说:绝大多数对象都是朝生夕灭的。
强分代假说:熬过越多次垃圾收集过程的对象就越难以消亡。

垃圾回收器:
常问的是CMS。
在这里插入图片描述
1.初始标记(STW)
2.并发标记(可以和用户线程并发执行)
3.重新标记(STW)
4.并发清除

G1垃圾收集器:
与CMS不同之处是将内存区域分成很多内存块,每个内存块可以担任eden,survivor,old,humongous中的任一角色,进行垃圾回收时也是由垃圾回收器判定最优的回收区域,来满足用户设定的垃圾回收时间。
在这里插入图片描述
1.初始标记(STW)
2.并发标记(可以和用户线程并发执行)
3.最终标记(STW)
4.筛选回收(STW)

涉及到跨代引用,垃圾回收器使用了卡表和remember set来进行处理,不展开讲了。
还有三色标记法会产生浮动垃圾(多标的情况),还会少标(增量更新法-CMS,原始快照法-G1)

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值