写点什么

中高级 Java 大厂高频面试题,已开源下载

发布于: 1 小时前

一、什么情况下会发生栈内存溢出?

1、栈是线程私有的,栈的生命周期和线程一样,每个方法在执行的时候就会创建一个栈帧,它包含局部变量表、操作数栈、动态链接、方法出口等信息,局部变量表又包括基本数据类型和对象的引用;2、当线程请求的栈深度超过了虚拟机允许的最大深度时,会抛出 StackOverFlowError 异常,方法递归调用肯可能会出现该问题;


3、调整参数-xss 去调整 jvm 栈的大小

二、详解 JVM 内存模型?


jvm 将虚拟机分为 5 大区域,程序计数器、虚拟机栈、本地方法栈、java 堆、方法区;


  • 程序计数器:线程私有的,是一块很小的内存空间,作为当前线程的行号指示器,用于记录当前虚拟机正在执行的线程指令地址;

  • 虚拟机栈:线程私有的,每个方法执行的时候都会创建一个栈帧,用于存储局部变量表、操作数、动态链接和方法返回等信息,当线程请求的栈深度超过了虚拟机允许的最大深度时,就会抛出 StackOverFlowError;

  • 本地方法栈:线程私有的,保存的是 native 方法的信息,当一个 jvm 创建的线程调用 native 方法后,jvm 不会在虚拟机栈中为该线程创建栈帧,而是简单的动态链接并直接调用该方法;

  • 堆:java 堆是所有线程共享的一块内存,几乎所有对象的实例和数组都要在堆上分配内存,因此该区域经常发生垃圾回收的操作;

  • 方法区:存放已被加载的类信息、常量、静态变量、即时编译器编译后的代码数据。即永久代,在 jdk1.8 中不存在方法区了,被元数据区替代了,原方法区被分成两部分;1:加载的类信息,2:运行时常量池;加载的类信息被保存在元数据区中,运行时常量池保存在堆中;

三、JVM 中一次完整的 GC 是什么样子的?对象如何晋升到老年代?


java 堆 = 新生代+老年代;新生代 = Eden + Suivivor(S0 + S1),默认分配比例是 8:1:1;当 Eden 区空间满了的时候,就会触发一次 Minor GC,以收集新生代的垃圾,存活下来的对象会被分配到 Survivor 区大对象(需要大量连续内存空间的对象)会直接被分配到老年代如果对象在 Eden 中出生,并且在经历过一次 Minor GC 之后仍然存活,被分配到存活区的话,年龄+1,此后每经历过一次 Minor GC 并且存活下来,年龄就+1,当年龄达到 15 的时候,会被晋升到老年代;当老年代满了,而无法容纳更多对象的话,会触发一次 full gc;full gc 存储的是整个内存堆(包括年轻代和老年代);;Major GC 是发生在老年代的 GC,清理老年区,经常会伴随至少一次 minor gc;

四、Java 中的垃圾回收算法?

java 中有四种垃圾回收算法,分别是标记清除法、标记整理法、复制算法、分代收集算法;


  • 标记清除法:第一步:利用可达性去遍历内存,把存活对象和垃圾对象进行标记;第二步:在遍历一遍,将所有标记的对象回收掉;特点:效率不行,标记和清除的效率都不高;标记和清除后会产生大量的不连续的空间分片,可能会导致之后程序运行的时候需分配大对象而找不到连续分片而不得不触发一次 GC;

  • 标记整理法:第一步:利用可达性去遍历内存,把存活对象和垃圾对象进行标记;第二步:将所有的存活的对象向一段移动,将端边界以外的对象都回收掉;特点:适用于存活对象多,垃圾少的情况;需要整理的过程,无空间碎片产生;

  • 复制算法:将内存按照容量大小分为大小相等的两块,每次只使用一块,当一块使用完了,就将还存活的对象移到另一块上,然后在把使用过的内存空间移除;特点:不会产生空间碎片;内存使用率极低;

  • 分代收集算法:根据内存对象的存活周期不同,将内存划分成几块,java 虚拟机一般将内存分成新生代和老生代,在新生代中,有大量对象死去和少量对象存活,所以采用复制算法,只需要付出少量存活对象的复制成本就可以完成收集;老年代中因为对象的存活率极高,没有额外的空间对他进行分配担保,所以采用标记清理或者标记整理算法进行回收;

五、如何判断一个对象是否存活?

判断一个对象是否存活,分为两种算法 1:引用计数法;2:可达性分析算法;


引用计数法:给每一个对象设置一个引用计数器,当有一个地方引用该对象的时候,引用计数器就+1,引用失效时,引用计数器就-1;当引用计数器为 0 的时候,就说明这个对象没有被引用,也就是垃圾对象,等待回收;缺点:无法解决循环引用的问题,当 A 引用 B,B 也引用 A 的时候,此时 AB 对象的引用都不为 0,此时也就无法垃圾回收,所以一般主流虚拟机都不采用这个方法;


可达性分析法从一个被称为 GC Roots 的对象向下搜索,如果一个对象到 GC Roots 没有任何引用链相连接时,说明此对象不可用,在 java 中可以作为 GC Roots 的对象有以下几种:


虚拟机栈中引用的对象方法区类静态属性引用的变量方法区常量池引用的对象本地方法栈 JNI 引用的对象但一个对象满足上述条件的时候,不会马上被回收,还需要进行两次标记;第一次标记:判断当前对象是否有 finalize()方法并且该方法没有被执行过,若不存在则标记为垃圾对象,等待回收;若有的话,则进行第二次标记;第二次标记将当前对象放入 F-Queue 队列,并生成一个 finalize 线程去执行该方法,虚拟机不保证该方法一定会被执行,这是因为如果线程执行缓慢或进入了死锁,会导致回收系统的崩溃;如果执行了 finalize 方法之后仍然没有与 GC Roots 有直接或者间接的引用,则该对象会被回收;

最后

分享一些系统的面试题,大家可以拿去刷一刷,准备面试涨薪。


请点赞后,戳这里,免费获取


这些面试题相对应的技术点:


  • JVM

  • MySQL

  • Mybatis

  • MongoDB

  • Redis

  • Spring

  • Spring boot

  • Spring cloud

  • Kafka

  • RabbitMQ

  • Nginx

  • ......


大类就是:


  • Java 基础

  • 数据结构与算法

  • 并发编程

  • 数据库

  • 设计模式

  • 微服务

  • 消息中间件











用户头像

VX:Lzzzzzz63 领取资料 2021.07.07 加入

还未添加个人简介

评论

发布
暂无评论
中高级Java大厂高频面试题,已开源下载