上周面了百度,问的很细~

· 浏览次数 : 0

小编点评

面试题目: 1. 请介绍一下您认为最有意义的项目?在这个项目中,您负责了哪些模块?项目的亮点是什么?您是如何解决遇到的棘手问题的? 2. synchronized 锁升级的过程是怎样的?JDK 1.6 和 JDK 15 有什么区别? 3. synchronized 作用在普通方法和静态方法上有什么区别?synchronized 实现原理是什么? 4. volatile 作用和实现原理是什么?volatile 如何保证内存可见性和有序性? 5. JVM 内存布局是怎样的?栈和方法区会出现 OOM 吗? 6. 父线程创建多个子线程可能会导致哪块内存溢出?如何在设计中避免这种情况? 7. CMS 和 G1 收集器的区别是什么?它们各自适用于哪些场景? 8. 请描述一下创建一个对象的过程。 答案: 1. 请介绍一下您认为最有意义的项目?在这个项目中,您负责了哪些模块?项目的亮点是什么?您是如何解决遇到的棘手问题的? 答:在我认为最有意义的项目中,我负责了一个微服务项目,主要负责了服务的接口设计和实现。项目的亮点在于我们采用了分布式事务解决方案,保证了数据的一致性。在遇到棘手问题时,我们通过团队讨论和查阅资料,最终找到了合适的解决方案。 2. synchronized 锁升级的过程是怎样的?JDK 1.6 和 JDK 15 有什么区别? 答:synchronized 锁升级分为四个阶段:无锁 - 偏向锁 - 轻量级锁 - 重量级锁。JDK 1.6 中,升级过程是:无锁 - 偏向锁 - 轻量级锁 - 重量级锁。而 JDK 15 中,升级过程是:无锁 - 轻量级锁 - 重量级锁。JDK 15 废除了偏向锁,因为它发现偏向锁在多核处理器下容易导致竞争不均衡。 3. synchronized 作用在普通方法和静态方法上有什么区别?synchronized 实现原理是什么? 答:synchronized 作用在普通方法是对象实例级别,而作用在静态方法是类级别,因此作用在静态方法时,锁范围更大、性能也更低。synchronized 的实现原理是通过 JVM 内置的 Monitor 监视器实现的,而 Monitor 是依赖操作系统的互斥锁 Mutex 实现的。 4. volatile 作用和实现原理是什么?volatile 如何保证内存可见性和有序性? 答:volatile 的作用有两个:保证内存可见性和保证有序性(禁止指令重排序)。内存可见性实现原理是通过 lock 前缀指令实现的,它会锁定当前内存区域的缓存并立即将数据写入主内存,回写主内存时会通过 MESI 协议使其他线程缓存失效。有序性实现原理是通过插入内存屏障,禁止重排序优化。 5. JVM 内存布局是怎样的?栈和方法区会出现 OOM 吗? 答:JVM 内存布局包括程序计数器、Java 虚拟机栈、本地方法栈、Java 堆和方法区。栈和方法区都会出现 OOM,它们的 OOM 发生场景分别是:栈内存超过最大深度或无法动态扩展;方法区存放的类、常量、静态变量等信息超过分配给它的内存大小。 6. 父线程创建多个子线程可能会导致哪块内存溢出?如何在设计中避免这种情况? 答:可能会导致内存溢出的区域有:Java 栈内存溢出、堆内存溢出和方法区溢出。为了避免这种情况,可以通过合理设置栈的大小、控制对象数量、使用线程池等技术来避免 OOM。 7. CMS 和 G1 收集器的区别是什么?它们各自适用于哪些场景? 答:CMS 是老年代垃圾回收器,目标是最短停顿时间;G1 是全代垃圾回收器,除了追求低停顿外,还允许用户设定期望的最大停顿时间。CMS 使用标记-清除算法,会产生内存碎片;G1 使用复制算法,不会有内存碎片。CMS 适用于小内存和 JDK 8 之前环境,而 G1 适用于大内存管理和 JDK 9+ 环境。 8. 请描述一下创建一个对象的过程。 答:创建一个对象的过程包括:类加载检查、分配内存空间、初始化零值、设置对象头和执行构造方法。对象创建成功意味着构造方法执行完成,对象已经准备好被使用。

正文

上周刚刚面了百度,问的问题不算很难,但却很细,我把这些面试题和答案都整理出来了,一起来看吧。

重点介绍一个你觉得有意义的项目?

回答技巧和思路:

  1. 介绍的项目业务难度和技术难点要高一些,最好是微服务项目。
  2. 简明扼要的讲清楚项目核心板块的业务场景即可,切忌不要讲的太细和太久,这只是面试官要考察你技术问题的一个触手。
  3. 讲清楚自己在项目中负责的模块。
  4. 讲清楚项目的亮点是啥。
  5. 讲清楚遇到了哪些棘手的问题?以及最终的解决方案。

synchronize锁升级过程?

synchronized 锁升级有两个版本:

  1. JDK 1.6 synchronized 锁升级:无锁 -> 偏向锁 -> 轻量级锁 -> 重量级锁。
  2. JDK 15 synchronized 锁升级:无锁 -> 轻量级锁 -> 重量级锁。

注意:回答的过程中,最好能讲明白每种锁的概念和特征,以及为什么 JDK 15 要废除偏向锁?

synchronize作用在普通方法和静态方法上有什么区别?

synchronized 作用在静态方法是类级别的,而作用在普通方法是对象实例级别,因此作用在静态方法时,锁范围更大、性能也更低。

synchronized实现原理?

synchronized 同步锁是通过 JVM 内置的 Monitor 监视器实现的,而监视器又是依赖操作系统的互斥锁 Mutex 实现的。

例如,以下代码中使用了 synchronized 修饰:

public class SynchronizedToMonitorExample {
    public static void main(String[] args) {
        int count = 0;
        synchronized (SynchronizedToMonitorExample.class) {
            for (int i = 0; i < 10; i++) {
                count++;
            }
        }
        System.out.println(count);
    }
}

当我们将上述代码编译成字节码之后,得到的结果是这样的:

从上述结果我们可以看出,在 main 方法中多了一对 monitorenter 和 monitorexit 的指令,它们的含义是:

  • monitorenter:表示进入监视器。
  • monitorexit:表示退出监视器。

由此可知 synchronized 是依赖 Monitor 监视器实现的。

volatile作用和实现原理?

volatile 作用有以下两个:

  1. 保证内存可见性;
  2. 保证有序性(禁止指令重排序)。

① 内存可见性实现原理

volatile 内存可见性主要通过 lock 前缀指令实现的,它会锁定当前内存区域的缓存(缓存行),并且立即将当前缓存行数据写入主内存(耗时非常短),回写主内存的时候会通过 MESI 协议使其他线程缓存了该变量的地址失效,从而导致其他线程需要重新去主内存中重新读取数据到其工作线程中。

什么 MESI 协议?

MESI 协议,全称为 Modified, Exclusive, Shared, Invalid,是一种高速缓存一致性协议。它是为了解决多处理器(CPU)在并发环境下,多个 CPU 缓存不一致问题而提出的。
MESI 协议定义了高速缓存中数据的四种状态:

  1. Modified(M):表示缓存行已经被修改,但还没有被写回主存储器。在这种状态下,只有一个 CPU 能独占这个修改状态。
  2. Exclusive(E):表示缓存行与主存储器相同,并且是主存储器的唯一拷贝。这种状态下,只有一个 CPU 能独占这个状态。
  3. Shared(S):表示此高速缓存行可能存储在计算机的其他高速缓存中,并且与主存储器匹配。在这种状态下,各个 CPU 可以并发的对这个数据进行读取,但都不能进行写操作。
  4. Invalid(I):表示此缓存行无效或已过期,不能使用。

MESI 协议的主要用途是确保在多个 CPU 共享内存时,各个 CPU 的缓存数据能够保持一致性。当某个 CPU 对共享数据进行修改时,它会将这个数据的状态从 S(共享)或 E(独占)状态转变为 M(修改)状态,并等待适当的时机将这个修改写回主存储器。同时,它会向其他 CPU 广播一个“无效消息”,使得其他 CPU 将自己缓存中对应的数据状态转变为I(无效)状态,从而在下次访问这个数据时能够从主存储器或其他 CPU 的缓存中重新获取正确的数据。

这种协议可以确保在多处理器环境中,各个 CPU 的缓存数据能够正确、一致地反映主存储器中的数据状态,从而避免由于缓存不一致导致的数据错误或程序异常。

② 有序性实现原理

volatile 的有序性是通过插入内存屏障(Memory Barrier),在内存屏障前后禁止重排序优化,以此实现有序性的。

什么是内存屏障?

内存屏障(Memory Barrier 或 Memory Fence)是一种硬件级别的同步操作,它强制处理器按照特定顺序执行内存访问操作,确保内存操作的顺序性,阻止编译器和 CPU 对内存操作进行不必要的重排序。内存屏障可以确保跨越屏障的读写操作不会交叉进行,以此维持程序的内存一致性模型。

在 Java 内存模型(JMM)中,volatile 关键字用于修饰变量时,能够保证该变量的可见性和有序性。关于有序性,volatile 通过内存屏障的插入来实现:

  • 写内存屏障(Store Barrier / Write Barrier): 当线程写入 volatile 变量时,JMM 会在写操作前插入 StoreStore 屏障,确保在这次写操作之前的所有普通写操作都已完成。接着在写操作后插入 StoreLoad 屏障,强制所有后来的读写操作都在此次写操作完成之后执行,这就确保了其他线程能立即看到 volatile 变量的最新值。
  • 读内存屏障(Load Barrier / Read Barrier): 当线程读取 volatile 变量时,JMM 会在读操作前插入 LoadLoad 屏障,确保在此次读操作之前的所有读操作都已完成。而在读操作后插入 LoadStore 屏障,防止在此次读操作之后的写操作被重排序到读操作之前,这样就确保了对 volatile 变量的读取总是能看到之前对同一变量或其他相关变量的写入结果。

通过这种方式,volatile 关键字有效地实现了内存操作的顺序性,从而保证了多线程环境下对 volatile 变量的操作遵循 happens-before 原则,确保了并发编程的正确性。

JVM内存布局?

《Java虚拟机规范》中将 JVM 运行时数据区域划分为以下 5 部分:

  1. 程序计数器(Program Counter Register):用于存储当前线程执行的字节码指令的地址,在多线程环境中,程序计数器用于实现线程切换,保证线程恢复执行时能够继续从正确的位置执行代码。
  2. Java 虚拟机栈(Java Virtual Machine Stacks):用于存储方法调用和局部变量(方法内部定义的变量),在方法调用和返回时,虚拟机栈用于保存方法的调用帧,包括方法的局部变量、操作数栈、方法返回地址等。
  3. 本地方法栈(Native Method Stack):与虚拟机栈类似,本地方法栈用于执行本地(Native)方法。
  4. Java 堆(Java Heap):JVM 中最大的一块内存区域,用于存储对象实例。所有的对象都在堆中分配内存。
  5. 方法区(Methed Area):用于存储类的元数据信息,包括类的结构、字段、方法、静态变量、常量池等。

如下图所示:
image.png

栈和方法区会有OOM吗?

栈和方法区都会出现 OOM,它们的 OOM 发生场景如下:

  • 栈内存主要用于存储方法的栈帧,包括局部变量、操作数栈、方法返回地址等。当一个线程请求的栈深度超过 JVM 允许的最大深度时(默认情况下这个值是比较大的,但可以通过-Xss参数调整),会抛出 StackOverflowError 异常。此外,如果 JVM 尝试动态扩展栈空间大小但无法获得足够的内存,也可能抛出 OutOfMemoryError 异常。不过,这种情况相对较少见,因为栈空间一般在启动时就已经固定或者有比较确定的上限。
  • 当方法区(或元空间)中存放的类、常量、静态变量等信息超过了 JVM 分配给它的内存大小时(可通过 -XX:MaxMetaspaceSize 等参数进行设置),就会抛出 OutOfMemoryError。特别是当应用动态加载大量的类或类加载器无法被垃圾回收时,容易出现方法区的内存溢出。

父线程创建多个子线程可能会导致哪块内存溢出?

可能会导致内存溢出的区域有以下几个:

  1. Java 栈内存溢出:每个线程都有自己的栈,用于存储方法调用时的方法信息、局部变量等数据。如果线程的栈设置过大,或者线程递归深度过深,可能会导致栈内存溢出(StackOverflowError)。若栈大小动态扩展受限于系统可用内存,则可能抛出 OutOfMemoryError。
  2. 堆内存溢出:当创建大量线程时,每个线程可能会创建和管理多个对象,这些对象都存储在堆中,当对象超过 JVM 配置的最大堆内存时(通过 -Xmx 参数设置),可能会导致 java.lang.OutOfMemoryError: Java heap space 错误。
  3. 方法区溢出: 在多线程应用中,当线程中的代码涉及到动态类加载(例如使用线程上下文类加载器加载不同的类)时,可能会导致方法区(或其替代品 Metaspace)内存的快速增长。方法区存储了类的元数据,如果这部分内存达到 JVM 配置的最大值(通过 -XX:MaxMetaspaceSize 设置),也会引发 java.lang.OutOfMemoryError,错误信息可能涉及“Metaspace”。

CMS和G1收集器的区别?

CMS 和 G1 区别主要有以下几个:

  1. 目标和定位不同:CMS 目标和定位是最短停顿时间;G1 除了追求低停顿外,还允许用户设定期望的最大停顿时间(Pause Time Target),更加灵活地平衡吞吐量和响应时间,适合大规模数据的应用。
  2. 作用区域不同:CMS 是老年代垃圾回收器;G1 是全代(新生代+老年代)垃圾回收器。
  3. 使用算法不同:CMS 使用的是“标记-清除”算法,所以会产生内存碎片;而 G1 使用的是“复制”算法所以不会有内存碎片。
  4. 适用场景不同:小内存和 JDK 8 之前通常会使用 CMS 垃圾回收器;而大内存管理和 JDK 9+ 以上环境通常会使用 G1 垃圾回收器。

说说创建一个对象的过程?

创建一个对象的过程如下:

  1. 类加载检查:当通过 new 关键字创建一个对象时,JVM 首先会检查该对象的类是否已经被加载并初始化了。如果尚未加载,JVM 将先进行类的加载过程,然后调用该类的构造器以完成初始化。
  2. 分配内存空间:类加载完成后,JVM 会在 Java 堆中为新创建的对象分配足够的内存空间。对象所需的内存大小在类加载过程中就已经确定。内存的分配方式取决于 Java 堆内存是否规整,可以选择“指针碰撞”或“空闲列表”两种不同的分配方式。
  3. 初始化零值:内存分配之后,JVM 会对对象的普通成员变量进行初始化为零值,比如 int 类型初始化为 0,Integer 类型初始化为 null。这一步骤确保了对象的成员字段在不经过显式初始化的情况下也能被直接使用。
  4. 设置对象头:然后 JVM 需要对对象的对象头进行设置,这包括对象的元数据信息、GC 分代年龄、 hashCode 以及锁标记等。对象头的设置对于对象的后续使用至关重要。
  5. 执行构造方法:最后,JVM 将执行对象的构造方法。这一步是开发者可以控制的,可以在构造方法中添加自定义的初始化代码,以实现特定的业务逻辑。构造方法执行完成后,一个完全初始化且可直接使用的对象才算创建成功。

注意:对象创建过程和类加载机制(加载、验证、准备、解析、初始化)略有不同。

本文已收录到我的面试小站 www.javacn.site,其中包含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、消息队列等模块。

与上周面了百度,问的很细~相似的内容:

上周面了百度,问的很细~

上周刚刚面了百度,问的问题不算很难,但却很细,我把这些面试题和答案都整理出来了,一起来看吧。 重点介绍一个你觉得有意义的项目? 回答技巧和思路: 介绍的项目业务难度和技术难点要高一些,最好是微服务项目。 简明扼要的讲清楚项目核心板块的业务场景即可,切忌不要讲的太细和太久,这只是面试官要考察你技术问题

上周热点回顾(9.18-9.24)

热点随笔: · 蜘蛛的依旧疯狂与园子的新畅想:尝试放出被屏蔽的百度蜘蛛网段 (博客园团队)· 逃不过转行的命运,与互联网无缘了 (哈er)· JDK21来了!附重要更新说明 (DaFanJoy)· 【逆向专题】【危!!!刑】(一)使用c#+Win32Api实现进程注入到wechat (四处观察)· 

iPhone 使用类ChatGPT应用的几种方法

# iPhone 使用类ChatGPT功能的几种方法 ## 背景 ``` 前几天使用edge的wetab的插件给自己的工作带来了很多帮助 尤其是一些基础shell语法以及sql语法, 比使用百度, bing 等搜素引擎更加方便快捷. 当时一直想能不能在手机上面也使用这样的软件. 当然了, 这个帖子仅

刷爆 LeetCode 双周赛 100,单方面宣布第一题最难

本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 提问。 大家好,我是小彭。 上周末是 LeetCode 第 100 场双周赛,你参加了吗?这场周赛整体没有 Hard 题,但是也没有 Easy 题。第一题国服前百名里超过一半人 wa,很少见。 小彭的技术交流群 02

某公司自动化测试3面

# 某公司自动化测试3面 > 仅供参阅,并不提供参考答案,上课的时候多数讲解过 > 算法题给了你一个参考,都是力扣上的 ## 一面 ```text 1. 自我介绍 2. 关于自动化:怎么做的,目前的进展,效果如何,遇到的困难 3. 你的框架搭建,最初是考虑了哪些因素去设计的 4. 如何维护自动化ca

抢先看!美团、京东、360等大厂面试题解析,技术面试必备。

技术面试必备!美团、京东、360等大厂面试题详解,让你轻松应对各大公司面试挑战! 往期硬核面经 哦耶!冲进腾讯了! 牛逼!上岸腾讯互娱和腾讯TEG! 腾讯的面试,强度拉满! 前几篇文章分享了上岸腾讯的最新面经。 不少粉丝股东留言说别只发腾讯的啦,其他大厂的也安排一些吧,比如美团、360、京东的。 必

腾讯安全

转载:腾讯安全杨光夫:从实战、智能化安全运营出发,实现安全免疫力建设进阶 腾讯安全积累了AI能力、威胁情报能力、攻防对抗三大原子能力。 攻防体系架建设 以攻促防的攻防体系建设进阶,核心要解决的痛点是发现和感知安全威胁的存在及可能性、解决资产暴露面问题、满足企业自主创新要求。 在流量检测与响应上,腾讯

计算机底层的秘密读书笔记之一

# 计算机底层的秘密读书笔记之一 ## 摘要 ``` 上周天在家休息时在知乎上面看到了影响性能的几个场景. 里面见到了cache的乒乓问题,以及cache line的伪共享问题. 知乎的答案里面图文并茂. 作者的思路也很清晰 就顺着水印找到了公众号还有作者刚出版的一本书. 京东周一快递到手后,这几天

记一次 .NET 某设备监控系统 死锁分析

一:背景 1. 讲故事 上周看了一位训练营朋友的dump,据朋友说他的程序卡死了,看完之后发现是一例经典的死锁问题,蛮有意思,这个案例算是学习 .NET高级调试 入门级的案例,这里和大家分享一下。 二:WinDbg 分析 1. 程序为什么会卡死 因为是窗体程序,所以看主线程的线程栈就好了,如果卡在

WPF网格类型像素着色器

由于WPF只能写像素着色器,没法写顶点着色器,所以只能在这上面做文章了 刚好有个纹理坐标TEXCOORD输入可用,而且值的范围是已知的0-1,左上角是原点,这就好办了 例子 索引 二分网格 使用ceil 0-1移动定义域到-0.5 - 0.5,然后向上取整变成 0 / 1 float4 main(f