2020---JVM面试题

目录

一、说一下jvm的运行时数据区

二、堆和栈的区别

三、怎样判断对象是否可以被回收

四、内存泄露与内存溢出的区别

五、java内存是怎么分配

六、垃圾回收的主要方法

七、java中有哪些引用

八、解释一下Object obj=new Object()

九、什么是类的加载

十、请解释下类的生命周期

十一、请介绍一下GC垃圾收集器

十二、StackOverFlow异常有没有遇到过

十三、OOM异常有没有遇到过

十四、什么时候触发Full GC


一、说一下jvm的运行时数据区

程序计数器:较小的内存空间,当前线程所执行的字节码行号指示器,唯一一个无OOM区域;

虚拟机栈:虚拟机栈和线程生命周期相同,一个线程每调用一个方法就创建一个栈针。

本地方法栈:虚拟机栈是服务 Java 方法的,而本地方法栈是为虚拟机调用 Native 方法服务的;

堆:Java 虚拟机中内存最大的一块,是被所有线程共享的,几乎所有的对象实例都在这里分配内存;

方法区:用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据;

二、堆和栈的区别

(1)堆的物理地址分配对象是不连续的;栈使用的是数据结构中的栈,先进后出的原则,物理地址分配是连续的。所以性能快;

(2)功能不同:栈是用来储存局部变量和方法调用,堆是用来存储java对象;

(3)堆内存是共享,栈是线程私有的;

(4)栈内存空间远小于堆内存;

(5)异常错误:栈内存或者堆内存不足都会抛出异常。堆:OOM,栈:SOF

三、怎样判断对象是否可以被回收

(1)引用计数法: 为每个对象创建一个引用计数,有对象引用时计数器+1,对象被释放时-1;计数器为0时可以被回收;解决不了循环引用的问题;

(2)可达性计算法:从 GC Roots 开始向下搜索,搜索所走过的路径称为引用链。当一个对象到 GC Roots 没有任何引用链相连时,则证明此对象是可以被回收的。

作为GcRoots对象:虚拟机栈中引用的对象;方法区类静态属性的对象;方法区常量池引用的对象;本地方法栈的JNI引用的对象

但当对象不可达GCroots,这个对象也不会被立马回收,如果该对象没有重写finalize()方法或finalize()已经被执行过则直接回收,否则将对象加入F-queue队列中,在这里finalize()方法被执行,之后进行第二次标记,如果对象仍然被GC则GC,否则移除队列。

四、内存泄露与内存溢出的区别

内存泄露:(强引用所指向的对象不会被回收,可能导致内存泄漏,虚拟机宁愿抛出OOM也不会去回收他指向的对象)(1)对象是可达的(一直被引用)(2)对象不会被使用,不会被GC回收,却一直占用内存;

内存溢出:(系统已经不能再分配出你所需要的空间)(1)大量jar、class文件加载,装载类的空间不够;(2)操作大量对象导致堆内存空间用满

五、java内存是怎么分配

(1)对象优先分配在Eden区;(2)大对象直接进入老年代;(3)长期存活的对象进入老年代

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

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

六、垃圾回收的主要方法

(1)标记清除:会产生大量不连续的内存碎片,导致以后程序分配较大对象时,没有充足的连续内存而提前一次触发GC操作;

(2)复制算法:内存分成A、B两块,A负责分配对象,B不分配,A中存活的对象复制到区域B,在清理掉A中对象。每次回收都要浪费一半的内存;

(3)标记整理:将可回收的对象移动到另一端,紧密排列,在清理掉另一端的所有区域。仍需要进行局部对象移动,一定程度上降低了效率

(4)分代收集:

经过一次minor Gc 后,将Eden和survivor中还存活的对象一次性的复制到另一块survivor空间上了,最后清理掉Eden和刚才用过的survivor空间,将此时在survivor活下来的对象的年龄设置为1,以后每个survivor区熬过一次GC,年龄就加1,当对象的年龄达到15时,就把他们移动到老年代。

七、java中有哪些引用

强引用:发生GC的时候不会被回收;

弱引用:有用但不是必须的对象,发生内存溢出之前会被回收;

软引用:有用但不是必须的对象,在下一次GC会被回收;

虚引用:无法通过虚引用获得对象。

八、解释一下Object obj=new Object()

这里涉及java堆、方法区、java栈内存区域之间的关联

Object obj将反映到Java栈的本地变量表,obj是引用类型;

new Object()反映在java堆中,存储了Object类型的所有数据;

程序运行,类型信息就会加载在内存里,这些数据是在java方法区中。

九、什么是类的加载

类的加载就是将类的.class文件的二进制数据读入到内存中,将其放在运行时的方法区中,然后在堆里创建Class对象,用来封装在方法区内的数据结构。

双亲委派机制:类加载器收到类加载请求,自己不加载,向上委托给父类加载,父类加载不了,再自己加载。

十、请解释下类的生命周期

加载:查找并加载类的二进制文件,在堆中创建Class对象;

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

初始化:对静态变量和静态代码块执行初始化工作。

十一、请介绍一下GC垃圾收集器

Serial New 串行收集器是最古老,最稳定以及效率高的收集器,可能会产生较长的停顿,只使用一个线程去回收

Parallel New(并行)收集器,ParNew收集器其实就是Serial收集器的多线程版本

Parallel Scavenge(并行)收集器,Parallel Scavenge收集器类似ParNew收集器,Parallel收集器更关注系统的吞吐量

Serial Old(串行)收集器,新生代采用复制,老年代采用标记清理

Parallel Old(并行)收集器,Parallel Old是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法

CMS收集器,CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器

十二、StackOverFlow异常有没有遇到过

栈内存溢出,一般由于栈内存的局部变量过爆了,导致内存溢出,出现递归方法,递归过深,递归没有出口。

十三、OOM异常有没有遇到过

permgen space、heap space 错误

常见原因:(1)内存加载的数据量太大:一次性从数据库中读取太多数据;(2)启动参数堆内存值太小

(3)集合类中有对对象的引用,使用后未清空,GC不能进行回收

十四、什么时候触发Full GC

(1)老年代空间不足:如果创建一个大对象,Eden区域放不下这个大对象,会直接保存在老年代中;如果老年代空间也不足,则会触发Full GC;

(2)调用system.GC();

(3)持久代空间不足:当系统中加载类、反射的类和调用的方法较多时,永久代可能会占满;

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值