Java面试题库,2021Java大厂面试真题
前言
Spring 也算有多年的历史了,已成为Java应用程序开发框架的事实标准。在如此悠久的历史背景下,有人可能会认为Spring放慢了脚步,躺在了自己的荣誉簿上,再也做不出什么新鲜的东西,或者是让人激动的东西。甚至有人说,Spring是遗留项目,是时候去看看其他创新的东西了。
这些人说得不对。
Spring的生态圈里正在出现很多让人激动的新鲜事物,涉及的领域涵盖云计算、大数据、无模式的数据持久化、响应式编程以及客户端应用程序开发。
而大厂面试更是年年不会落下问SpringBoot,你还在怕搞不懂SpringBoot吗?以下是小编好时间心思整理的Spring大厂面试从基础到深入必懂知识点,分享出来给大家学习阅读,查漏补缺,也预祝大家面试顺利!
Java虚拟机内存模型
Java虚拟机内存模型中定义的访问操作与物理计算机处理的基本一致!
Java中通过多线程机制使得多个任务同时执行处理,所有的线程共享JVM内存区域main memory,而每个线程又单独的有自己的工作内存,当线程与内存区域进行交互时,数据从主存拷贝到工作内存,进而交由线程处理(操作码+操作数)。更多信息我们会在后面的《深入JVM—JVM类执行机制中详细解说》。
在之前,我们也已经提到,JVM的逻辑内存模型如下:
我们现在来逐个的看下每个到底是做什么的!
1、程序计数器
程序计数器(Program Counter Register)是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的行号指示器。在虚拟机的概念模型里(仅是概念模型,各种虚拟机可能会通过一些更高效的方式去实现),字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。
由于Java 虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)只会执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间的计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存。
如果线程正在执行的是一个Java 方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是Natvie 方法,这个计数器值则为空(Undefined)。此内存区域是唯一一个在Java 虚拟机规范中没有规定任何OutOfMemoryError 情况的区域。
2、Java 虚拟机栈
与程序计数器一样,Java 虚拟机栈(Java Virtual Machine Stacks)也是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是Java 方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame ①)用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
经常有人把Java 内存区分为堆内存(Heap)和栈内存(Stack),这种分法比较粗糙,Java 内存区域的划分实际上远比这复杂。这种划分方式的流行只能说明大多数程序员最关注的、与对象内存分配关系最密切的内存区域是这两块。其中所指的“堆”在后面会专门讲述,而所指的“栈”就是现在讲的虚拟机栈,或者说是虚拟机栈中的局部变量表部分。
局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference 类型,它不等同于对象本身,根据不同的虚拟机实现,它可能是一个指向对象起始地址的引用指针,也可能指向一个代表对象的句柄或者其他与此对象相关的位置)和returnAddress 类型(指向了一条字节码指令的地址)。
其中64 位长度的long 和double 类型的数据会占用2 个局部变量空间(Slot),其余的数据类型只占用1 个。局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在帧中分配多大的局部变量空间是完全确定的,在方法运行期间不会改变局部变量表的大小。
在Java 虚拟机规范中,对这个区域规定了两种异常状况:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError 异常;如果虚拟机栈可以动态扩展(当前大部分的Java 虚拟机都可动态扩展,只不过Java 虚拟机规范中也允许固定长度的虚拟机栈),当扩展时无法申请到足够的内存时会抛出OutOfMemoryError 异常。
3、本地方法栈
本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java 方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native 方法服务。虚拟机规范中对本地方法栈中的方法使用的语言、使用方式与数据结构并没有强制规定,因此具体的虚拟机可以自由实现它。甚至有的虚拟机(譬如Sun HotSpot 虚拟机)直接就把本地方法栈和虚拟机栈合二为一。
与虚拟机栈一样,本地方法栈区域也会抛出StackOverflowError 和OutOfMemoryError异常。
4、Java 堆
对于大多数应用来说,Java 堆(Java Heap)是Java 虚拟机所管理的内存中最大的一块。Java 堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。这一点在Java 虚拟机规范中的描述是:所有的对象实例以及数组都要在堆上分配①,但是随着JIT 编译器的发展与逃逸分析技术的逐渐成熟,栈上分配、标量替换②优化技术将会导致一些微妙的变化发生,所有的对象都分配在堆上也渐渐变得不是那么“绝对”了。
Java 堆是垃圾收集器管理的主要区域,因此很多时候也被称做“GC 堆”(GarbageCollected Heap,幸好国内没翻译成“垃圾堆”)。如果从内存回收的角度看,由于现在收集器基本都是采用的分代收集算法,所以Java 堆中还可以细分为:新生代和老年代;再细致一点的有Eden 空间、From Survivor 空间、To Survivor 空间等。如果从内存分配的角度看,线程共享的Java 堆中可能划分出多个线程私有的分配缓冲区(Thread LocalAllocation Buffer,TLAB)。不过,无论如何划分,都与存放内容无关,无论哪个区域,存储的都仍然是对象实例,进一步划分的目的是为了更好地回收内存,或者更快地分配内存。在本章中,我们仅仅针对内存区域的作用进行讨论,Java 堆中的上述各个区域的分配和回收等细节将会是下一章的主题。
根据Java 虚拟机规范的规定,Java 堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可,就像我们的磁盘空间一样。在实现时,既可以实现成固定大小的,也可以是可扩展的,不过当前主流的虚拟机都是按照可扩展来实现的(通过-Xmx和-Xms 控制)。如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError 异常。
4、方法区
方法区(Method Area)与Java 堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然Java 虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做Non-Heap(非堆),目的应该是与Java 堆区分开来。
对于习惯在HotSpot 虚拟机上开发和部署程序的开发者来说,很多人愿意把方法区称为“永久代”(Permanent Generation),本质上两者并不等价,仅仅是因为HotSpot 虚拟机的设计团队选择把GC 分代收集扩展至方法区,或者说使用永久代来实现方法区而已。对于其他虚拟机(如BEA JRockit、IBM J9 等)来说是不存在永久代的概念的。即使是HotSpot 虚拟机本身,根据官方发布的路线图信息,现在也有放弃永久代并“搬家”至Native Memory 来实现方法区的规划了。
Java 虚拟机规范对这个区域的限制非常宽松,除了和Java 堆一样不需要连续的内存和可以选择固定大小或者可扩展外,还可以选择不实现垃圾收集。相对而言,垃圾收集行为在这个区域是比较少出现的,但并非数据进入了方法区就如永久代的名字一样“永久”存在了。这个区域的内存回收目标主要是针对常量池的回收和对类型的卸载,一般来说这个区域的回收“成绩”比较难以令人满意,尤其是类型的卸载,条件相当苛刻,但是这部分区域的回收确实是有必要的。在Sun 公司的BUG 列表中,曾出现过的若干个严重的BUG 就是由于低版本的HotSpot 虚拟机对此区域未完全回收而导致内存泄漏。
根据Java 虚拟机规范的规定,当方法区无法满足内存分配需求时,将抛出OutOfMemoryError 异常。
5、运行时常量池
运行时常量池(Runtime Constant Pool)是方法区的一部分。Class 文件中除了有类的版本、字段、方法、接口等描述等信息外,还有一项信息是常量池(Constant PoolTable),用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。
Java 虚拟机对Class 文件的每一部分(自然也包括常量池)的格式都有严格的规定,每一个字节用于存储哪种数据都必须符合规范上的要求,这样才会被虚拟机认可、装载和执行。但对于运行时常量池,Java 虚拟机规范没有做任何细节的要求,不同的提供商实现的虚拟机可以按照自己的需要来实现这个内存区域。不过,一般来说,除了保存Class 文件中描述的符号引用外,还会把翻译出来的直接引用也存储在运行时常量池中①。
运行时常量池相对于Class 文件常量池的另外一个重要特征是具备动态性,Java 语言并不要求常量一定只能在编译期产生,也就是并非预置入Class 文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用得比较多的便是String 类的intern() 方法。
既然运行时常量池是方法区的一部分,自然会受到方法区内存的限制,当常量池无法再申请到内存时会抛出OutOfMemoryError 异常
6、直接内存
直接内存(Direct Memory)并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,但是这部分内存也被频繁地使用,而且也可能导致OutOfMemoryError 异常出现,所以我们放到这里一起讲解。
在JDK 1.4 中新加入了NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O 方式,它可以使用Native 函数库直接分配堆外内存,然后通过一个存储在Java 堆里面的DirectByteBuffer 对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在Java 堆和Native 堆中来回复制数据。
显然,本机直接内存的分配不会受到Java 堆大小的限制,但是,既然是内存,则肯定还是会受到本机总内存(包括RAM 及SWAP 区或者分页文件)的大小及处理器寻址空间的限制。服务器管理员配置虚拟机参数时,一般会根据实际内存设置-Xmx等参数信息,但经常会忽略掉直接内存,使得各个内存区域的总和大于物理内存限制(包括物理上的和操作系统级的限制),从而导致动态扩展时出现OutOfMemoryError异常
逻辑内存模型我们已经看到了,那当我们建立一个对象的时候是怎么进行访问的呢?在Java 语言中,对象访问是如何进行的?对象访问在Java 语言中无处不在,是最普通的程序行为,但即使是最简单的访问,也会却涉及Java 栈、Java 堆、方法区这三个最重要内存区域之间的关联关系,如下面的这句代码:
Object obj = new Object();
假设这句代码出现在方法体中,那“Object obj”这部分的语义将会反映到Java 栈的本地变量表中,作为一个reference 类型数据出现。而“new Object()”这部分的语义将会反映到Java 堆中,形成一块存储了Object 类型所有实例数据值(Instance Data,对象中各个实例字段的数据)的结构化内存,根据具体类型以及虚拟机实现的对象内存布局(Object Memory Layout)的不同,这块内存的长度是不固定的。另外,在Java 堆中还必须包含能查找到此对象类型数据(如对象类型、父类、实现的接口、方法等)的地址信息,这些类型数据则存储在方法区中。
由于reference 类型在Java 虚拟机规范里面只规定了一个指向对象的引用,并没有定义这个引用应该通过哪种方式去定位,以及访问到Java 堆中的对象的具体位置,因此不同虚拟机实现的对象访问方式会有所不同,主流的访问方式有两种:使用句柄和直接指针。
句柄池
如果使用句柄访问方式,Java 堆中将会划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据和类型数据各自的具体地址信息,如下图所示。
如果使用直接指针访问方式,Java 堆对象的布局中就必须考虑如何放置访问类型数据的相关信息,reference 中直接存储的就是对象地址,如下图所示
这两种对象的访问方式各有优势,使用句柄访问方式的最大好处就是reference 中存储的是稳定的句柄地址,在对象被移动(垃圾收集时移动对象是非常普遍的行为)时只会改变句柄中的实例数据指针,而reference 本身不需要被修改。
使用直接指针访问方式的最大好处就是速度更快,它节省了一次指针定位的时间开销,由于对象的访问在Java 中非常频繁,因此这类开销积少成多后也是一项非常可观的执行成本。就本书讨论的主要虚拟机Sun HotSpot 而言,它是使用第二种方式进行对象访问的,但从整个软件开发的范围来看,各种语言和框架使用句柄来访问的情况也十分常见。
下面我们来看几个示例
1、Java 堆溢出
下面的程中我们限制Java 堆的大小为20MB,不可扩展(将堆的最小值-Xms 参数与最大值-Xmx 参数设置为一样即可避免堆自动扩展),通过参数-XX:+HeapDumpOnOutOfMemoryError 可以让虚拟机在出现内存溢出异常时Dump 出当前的内存堆转储快照以便事后进行分析。
参数设置如下
最后
整理的这些资料希望对Java开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。
再免费分享一波我的Java专题面试真题+视频学习详解+Java进阶学习书籍
[外链图片转存中…(img-TYoOaVOG-1621223380033)]
再免费分享一波我的Java专题面试真题+视频学习详解+Java进阶学习书籍
其实面试这一块早在第一个说的25大面试专题就全都有的。以上提及的这些全部的面试+学习的各种笔记资料,我这差不多来回搞了三个多月,收集整理真的很不容易,其中还有很多自己的一些知识总结。正是因为很麻烦,所以对以上这些学习复习资料感兴趣,
Java面试题库,2021Java大厂面试真题相关推荐
- 2022软件测试面试题 200道大厂面试真题 刷完拿到10k职位
系列文章目录 提示:阅读本章之前,请先阅读目录 文章目录 系列文章目录 前言 1. 编写测试用例时,一般会用到哪些方法进行测试用例的设计? 2. 测试过程中,为什么要做接口测试? 3. 测试过程中,如 ...
- 软件测试面试题:数据库大厂面试真题
一.数据库 1.为什么select * 这种方式效率低? 1.1不需要的列会增加时间传输时间和网络开销,尤其是大类型的字段:text varchar 1.2对于无用的大字段,会增加IO操作 1.3 ...
- 2020Android大厂高频面试题(字节跳动+阿里+华为+小米等20家大厂面试真题)附面经!
Android大厂高频面试题 1. 下列哪些语句关于内存回收的说明是正确的? ( ) A. 程序员必须创建一个线程来释放内存 B.内存回收程序负责释放无用内存 C.内存回收程 ...
- 「我有一剑可开天门」大厂面试真题,这边建议是直接开冲
前言 说一下,最新在重温雪中悍刀行这本小说,故此有了这么一个沙雕标题(小声bb.这本书是真的好看),这套面试题是一个粉丝总结完发给我的,本意是想让我分享出来帮助到更多的人,我整理了一下,算是比较详细, ...
- 这份大厂面试真题之蚂蚁金服,已经通过很多内部人员的证实!建议收藏 ,反复观看!(一)
后续会更新大厂面试真题之蚂蚁金服二哦 目录 1. jdk1.7 到 jdk1.8 Map 发生了什么变化(底层)? 2. ConcurrentHashMap 3. 并行跟并发有什么区别? 4. jdk ...
- b类 蚂蚁金服_这份大厂面试真题之蚂蚁金服,已经通过很多内部人员的证实!建议收藏 ,反复观看!(一)...
后续会更新大厂面试真题之蚂蚁金服二哦 1. jdk1.7 到 jdk1.8 Map 发生了什么变化(底层)? 1.8 之后 hashMap 的数据结构发生了变化,从之前的单纯的数组+链表结构变成数组+ ...
- 一起看看这些大厂面试真题查漏补缺吧,专题解析
前言 职场的金三银四跳槽季又来了,不同的是今年比往年「冷」一些,形式更加严峻一些,大家多多少少可能都听到或看到一些信息,就是好多公司在优化裁员,作为求职者来说,面试是一道坎,很多人会恐惧面试,即使是工 ...
- 货拉拉sql互联网大厂面试真题在线练习
货拉拉sql面试真题在线练习 一.sql刷题目的 二.互联网大厂货拉拉sql面试题 1.货拉拉sql数据表介绍 2.货拉拉订单练习题sql语句 (1)用车方和司机被禁止(banned=1)的比率分别为 ...
- 7.牛批了 Android 2022高级资深面试题 一线大厂和二线大厂面试真题精选 (大疆 附答案)第七套 30k+
笔者是面霸,面试500+场 当过考官:面过别人500+场 去过500强,也呆过初创公司. 斩获腾讯.华为.字节跳动,蚂蚁金服,OPPO,美团,安卓岗offer!我有一套速通大厂技巧 ...
最新文章
- java日期比较大小_java日期大小比较
- Git安装配置(Linux)
- 【Java8新特性】浅谈方法引用和构造器引用
- 德勤:2018年科技、传媒和电信行业未来趋势预测
- redis实现cache系统实践(六)
- 清华大学《操作系统》(二十):死锁和进程通信
- 清除服务器上传队列的文件,webUploader上传demo
- tensorflow之lenet训练手写字及应用
- HashPasswordForStoringInConfigFile 已过时
- Trust Region Policy Optimization (TRPO) 背后的数学原理
- Busybox是什么?
- editview软键盘弹出和隐藏
- oracle服务怎么手动删除,彻底删除oracle服务
- 2022电工(技师)考试题库模拟考试平台操作
- QuartusII13.1 操作
- html5小游戏猴子爬树源码,猴子爬树小班教案
- Nvidia TX2 串口使用
- 【SonarQube】安装、配置与使用 01
- 如何使用Python还原村上春树笔下经典的那句“我爱你像爱春天的小熊”
- 异常检测中的浅层模型与深度学习模型综述(A Unifying Review of Deep and Shallow Anomaly Detection)
热门文章
- Skywalking调用链监控系统 及 日志采集
- ABAP using与changing超详解 传值 技巧 使用习惯
- css设置三角形的旋转方法2以及箭头三角形的设置和旋转
- EasyDSS修改RTMP推流端口后直播无法回放录像问题优化
- win7 网络和共享中心提示“依赖服务或组无法启动” 解决方法
- 澜讯 | 时尚集团携手数澜科技 引领传统内容数字化新风潮
- 归约、分组与分区,深入讲解JavaStream终结操作
- python中input函数使用
- 保存图片到相册/图库___Android基础篇
- java调用公安接口_Java程序模拟公安局人员管理系统-----来自狼腾测试员