共计 2908 个字符,预计需要花费 8 分钟才能阅读完成。
前言
随着阿巴阿巴在面试中愈战愈勇,这几天又约上面试了,这次面试官让她谈谈对 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 的常识。
❤️/ 感激反对 /
以上便是本次分享的全部内容,心愿对你有所帮忙 ^_^
喜爱的话别忘了 分享、点赞、珍藏 三连哦~
欢送关注公众号 程序员巴士,来自字节、虾皮、招银的三端兄弟,分享编程教训、技术干货与职业规划,助你少走弯路进大厂。