前言
随着阿巴阿巴在面试中愈战愈勇,这几天又约上面试了,这次面试官让她谈谈对JVM的了解。
回家等告诉
面试官: 你对JVM的内存模型理解吗?是否讲讲外面的细节呢?
阿巴阿巴: JAVA虚拟机在执行JAVA程序的过程中,会把所有它治理的内存划分为若干个不同的数据区域,这些区域都有着各自的用处。
依据《JAVA 虚拟机标准SE 7 版》的规定,JAVA虚拟机所治理的内存将包含以下几个运行时的数据区域:堆、办法区、虚拟机栈、本地办法栈、程序计数器。
面试官: 那你能给我大略的介绍下这几区域吗?
阿巴阿巴: 办法区次要寄存的是虚拟机加载的类信息、常量、动态变量,堆区域次要是寄存对象的,虚拟机栈是用来寄存办法运行时产生的栈帧的,本地办法栈则是用来寄存本地办法(native)办法运行时产生的栈帧的,程序计数器是用于寄存下一条指令所在单元的地址的中央。
面试官: 不错,那你晓得什么时候栈内存会产生溢出嘛?
阿巴阿巴: 嗯,,,如果线程的栈深度大于虚拟机运行的最大深度,将抛出StackOverflowError异样,经常呈现于递归的办法调用。
面试官: 那还有其余状况会呈现栈内存溢出嘛?
阿巴阿巴: 如同没有其余状况了......
面试官: 堆的分代能够细讲一下嘛?
阿巴阿巴: 堆的话次要进行了一个分代,分成新生代、老年代、长久代。
阿巴阿巴: 新生代次要存一些朝生夕死的对象,老年代存的是比较稳定的对象或者是大对象,长久代用于寄存用于寄存动态文件,现在Java类、办法等。
面试官: 好的、那明天的面试就到这里吧,你先回去等告诉哈。
阿巴阿巴: 好的。
当场拿offer
阿巴阿巴: 你对JVM的内存模型理解吗?是否讲讲外面的细节呢?
阿巴阿巴: JAVA虚拟机在执行JAVA程序的过程中,会把所有它治理的内存划分为若干个不同的数据区域,这些区域都有着各自的用处。
依据《JAVA 虚拟机标准SE 7 版》的规定,JAVA虚拟机所治理的内存将包含以下几个运行时的数据区域:堆、办法区、虚拟机栈、本地办法栈、程序计数器。
面试官: 那你能给我大略的介绍下这几区域吗?
阿巴阿巴: 办法区次要寄存的是虚拟机加载的类信息、常量、动态变量,堆区域次要是寄存对象的,虚拟机栈是用来寄存办法运行时产生的栈帧的,本地办法栈则是用来寄存本地办法(native)办法运行时产生的栈帧的,程序计数器是用于寄存下一条指令所在单元的地址的中央。
面试官: 不错,那你晓得什么时候栈内存会产生溢出嘛?
阿巴阿巴: 有2种状况,第一种状况:如果线程的栈深度大于虚拟机运行的最大深度,将抛出StackOverflowError异样,经常呈现于递归的办法调用。还有一种状况:如果不停的创立线程,这样每个线程都会占用肯定的空间,最初导致栈空间有余,报OOM异样。JVM的这几个区域里,堆、办法区、本地办法栈、虚拟机栈都有可能会呈现OOM的一个异样。而程序计数器是惟一一个不会产生OOM的区域。
面试官: 能够啊,那再讲讲堆的散布呗!
阿巴阿巴: 堆次要分为新生代、老年代和长久代,这个长久代在JDK1.8版本的时候曾经划出了堆内存了,应用元空间来代替,元空间曾经不在JVM中,应用的是本地内存。
阿巴阿巴: 新生代次要存一些朝生夕死的对象,老年代存的是比较稳定的对象或者是大对象,长久代用于寄存用于寄存动态文件,现在Java类、办法等。
阿巴阿巴: 新生代的分区。
阿巴阿巴: 新生代分成Eden区和survivor区,其中survivor区又分为(s0和s1)俩个区域,它们的比例如图所示为8 : 1 : 1。新对象优先会在Eden区进行调配,如果是大对象那就间接进入老年代,当Eden区产生GC时,幸存的对象就会转入Survivor区,当在Survivor区中的对象的年龄达到设定的阈值时(默认是15),达到后就会被转入到老年代区域中。
面试官: 哪些区域是线程共享的,哪些区域是线程公有的呢?
阿巴阿巴: 办法区和堆区是线程共享的,虚拟机栈、本地办法栈、程序计数器这三个区域是线程公有的。
面试官: 既然堆事共享的,那么新生成对象时,堆外面的内存空间就有可能被多线程进行竞争,JVM在这一块是如何保障线程平安的呢?
阿巴阿巴: 这个嘛,JVM采纳了2种形式来解决,1应用的是指针碰撞,即CAS进行内存空间的竞争,而且JVM还会保护一个闲暇列表,来疾速找到闲暇的内存。同时JVM还会采纳TLAB,Thread Local Allocation Buffer,即线程本地调配缓存区的形式,将Eden区的局部内存让线程公有,当须要创立新对象的时候应用这部分线程公有的空间来调配给对象,这样能够缩小竞争带来的额定开销。
面试官: 那对象都是调配到堆里的嘛?
阿巴阿巴: 绝大多数对象都是调配在堆外面的,然而也有非凡状况,能够将对象在栈上调配,如果想要将对象的调配到栈上,那么就须要进行逃逸剖析。
阿巴阿巴: 逃逸剖析的根本行为就是剖析对象的作用域,当一个对象在办法中被定义后,如果这个对象被援用到办法的内部,或者能被其余线程给拜访到,那么称这个对象逃逸了。
阿巴阿巴: 如果确定了一个对象不会逃逸出办法之外,咱们就能够将这个对象的内存调配到栈上,那么这个对象的内存空间就能够随着栈帧的的生命周期而变动,一起创立一起沦亡,这样能够缩小堆的累赘,进步GC的性能,从而进步程序的运行效率。
阿巴阿巴: 然而逃逸剖析默认是不关上的,因为逃逸剖析须要对对象的作用域进行大量的计算,从而来判断对象是否会逃逸,而这种计算又会对性能造成影响,所以栈上调配实现起来比较复杂,个别不应用。用户能够应用参数 -XX : +DoEsapeAnalysis来手动开启逃逸剖析。
面试官: 你对内空间配担保这块相熟吗?
面试官: 空间调配担保个别呈现在Minor GC的时候,Minor GC后会将符合条件的对象转移到老年代,如果老年代最大可用的间断空间大于新生代的所有对象的所占空间总和,那么这次Minor GC将会被认为是平安的,如果小于,那么JVM则会查看Handle配置HandlePromotionFailure设置值是否容许担保失败。如果HandlePromotionFailure=true,那么会持续查看老年代最大可用间断空间是否大于历次降职到老年代的对象的均匀大小,如果大于,则尝试进行一次Minor GC,但这次Minor GC仍然是有危险的;如果小于或者HandlePromotionFailure=false,则改为进行一次Full GC。
面试官: 有理解过GC算法和垃圾回收器吗?
阿巴阿巴: 有的,GC算法次要分为上面这几类(滴滴滴。。。这时候面试官的电话响了)
面试官: 要不明天先这样,面试通过了,今天过去二面吧~
阿巴阿巴: 好哒。
总结
分享了一波JVM相干的高频面试题,理解JVM的一个模型机外部的一些根本机制,包含对象内存的调配,线程公有和共享相干的问题。
小巴由此开启了JVM相干的面试之旅,于是她回家天天恶补对于JVM的常识。
❤️/ 感激反对 /
以上便是本次分享的全部内容,心愿对你有所帮忙^_^
喜爱的话别忘了 分享、点赞、珍藏 三连哦~
欢送关注公众号 程序员巴士,来自字节、虾皮、招银的三端兄弟,分享编程教训、技术干货与职业规划,助你少走弯路进大厂。