0
点赞
收藏
分享

微信扫一扫

美团面试真

boomwu 2022-04-29 阅读 151

1.Spring AOP 底层原理

aop底层是采用动态代理机制实现的:接口+实现类

  • 如果要代理的对象,实现了某个接口,那么Spring AOP会使用JDK proxy创建代理对象
  • 没有实现接口的对象,会使用Cglib生成一个被代理对象的子类作为代理
    就是由代理创建出一个和impl实现类平级的一个对象,但是这个对象不是一个真正的对象,只是一个代理对象,但它可以实现和impl相同的功能,这个就是aop的横向机制原理,这样就不需修改源代码

2.HashMap的底层数据结构是怎样的?

JDK1.8之前

  • JDK1.8之前 HashMap底层是数组和链表结合在一起使用也就是链表散列

JDK1.8之后

  • 当链表长度大于8,会首先调用treefyBin()方法。这个方法会根据HashMap数组来决定是否可以转换红黑树。只有当数组长度大于或者等于64的情况下,才会执行转换操作,以减少搜索时间。否则只是执行resize()方法对数组进行扩容。

3.HashMap的扩容机制是怎样的

一般情况下,当元素数量超过阈值时便会触发扩容。每次扩容的容量都是之前容量的2倍。HashMap的容量是有上限的,必须小于1<<30。如果容量超出这个数,则不再增长,切阈值会被设置为Integer.MAX_VALUE.
JDK1.7之前 新容量 = 旧容量*2,新阈值 = 新容量 *负载因子
JDK1.8扩容机制。

4.ConcurrentHashMap的存储结构是怎样的

  • Java7 中concurrentHashMap使用的分段锁,也就是每一个segment上同时只有一个线程可以操作,每一个segment都是一个类似HashMap数组结构,它可以扩容,冲突会转化成链表。segment个数是16个
  • java 8中concurrentHashMap 使用synchronized锁+CAS机制,结构也从1.7的segment数组+hashentry数组+链表进化成了Node数组+链表/红黑树,Node是类似一个hashentry的结构。冲突再达到一定大小时会转化成红黑树,冲突小于一定数量时候又退化成链表。

5. 线程池大小如何设置

  • CPU密集型任务(N+1): 这种任务消耗主要是CPU资源,可以讲线程数量设置为N+1,比CPU核心数多出来一个线程是为了防止线程偶发的缺页中断,或者其他原因导致的任务暂时而暂停而带来的影响。一旦任务暂停,CPU就会处于空闲状态,而在这种情况下多出来的一个线程就可以充分利用CPU的空闲时间
  • I/O密集型任务(2N): 这种任务应用起来,系统会用大部分的时间来处理I/O交互,而线程在处理/O的时间段内不会占用CPU来处理,这时就可以将CPU交给其他线程使用。

6.IO密集型 线程数 = ncpu*2

7.G1收集器有哪些特点?

  • G1全称是Garbage-First,意为垃圾有限,哪一块的垃圾最多的优先清理它
  • G1 GC最主要的设计目标是: 将STW停顿的时间和分布,变成可预期且可配置的。被视为JDK1.7中hotspot虚拟机的一个重要进化特征,具有以下特点:
  • 并行与并发:G1能充分利用CPU、多核环境下的硬件优势,使用多个cpu来缩短stop-the-world停顿时间。部分其他收集器原本需要停顿Java线程执行GC动作,G1收集器仍然可以通过并发的方式让java程序继续执行。
  • 分代收集:虽然G1可以不需要其他收集器配合就能独立管理整个GC堆,但是还是保留了分代的概念。
  • 空间整合: 与CMS的标记清理算法不同,G1从整体看是基于标记-清理算法实现的收集器;从局部上看是基于标记复制算法实现的。
  • 可预测的停顿:这是G1相对于CMS的另一个优势,降低停顿时间是G1和CMS共同的关注点,但G1除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段內。
    G1收集器在后台维护了一个优先列表,每次根据允许的收集时间,优先选择回收价值最大的region

8.有哪些手段来排查OOM问题

  • 增加两个参数 -XX:+HeapDumpOnOutOfMemoryError --XX:HeapDumpPath=/tmp/headdump.hprof。当OOM发生时自动dump堆内信息到指定目录
  • 同时jstat查看JVM的内存和GC情况,先观察问题大概出在什么区域
  • 使用MAT工具载入到dump文件,分析大对象的占用情况,比如hashmap做缓存未清理,时间长了就会内存溢出,可以把改为弱引用

9.MySQL事物隔离级别,Mysql默认隔离级别是什么

默认可重复度

  • 读未提交-》脏读、幻读、不可重复读
  • 读已提交-〉幻读、不可重复读
  • 可重复度-》幻读
  • 串行化

10可重复度解决了哪些问题

可重复读的核心就是一致性读;保证多次读取同一个数据时候,其值都是和事物开始时候内容一致,禁止读取到别的事务未提交的数据,会造成幻读。而事务更新数据的时候,只能用当前读。如果当前的记录的行锁被其他事物占用的话,就需要进入等待锁。查询只承认在事务启动前提交完成的数据。

11.对sql的慢查询会考虑哪些优化?

  • 分析语句是否加载了不必要的字段/数据
  • 分析sql执行计划,思考可能的优化点,是否命中索引等
  • 查看sql涉及的表结构和索引信息
  • 如果sql很复杂,优化sql结构
  • 按照可能的优化点执行表结构的变更、增加索引、sql改写等操作
  • 查看优化后的执行时间和执行计划
  • 如果数据量太大,考虑分库分表
  • 利用缓存、减少查询次数

12. 谈一谈缓存穿透、缓存击穿和缓存雪崩,以及解决办法?

缓存穿透:

大量并发查询不存在的key,在缓存和数据库中都不存在,同时给缓存和数据库带来压力。一般有两种可能,业务数据被删除,导致缓存和数据库中都没有数据或者进行恶意ddos攻击
分析:为什么会多次透传呢?不存在一直为空,需要注意让缓存能够区分key不存在和查询到一个空值
解决办法:缓存空值的key,这样第一次不存在也会被加载记录,下次拿到这个key。可以使用bloom过滤器来判断key是否存在,如果bloom过滤器没有查询到这个数据,就不去数据库中查询。在处理请求前增加恶意请求检查,如果检测到恶意攻击,则拒绝进行服务。完全以缓存为准,使用异步加载策略,不会触发更新。

缓存击穿

某个key失效时候,正好有大量并发请求访问这个key
解决办法:key的更新操作添加全局互斥锁。完全以缓存为准,使用延迟异步加载的策略,这样就不会触发更新。

缓存雪崩

问题:当某一时刻发生大规模缓存失效的情况,导致大量的请求无法获取数据,从而将流量压力传导到数据库上,导致数据库压力过大甚至宕机。
原因:一般而言,缓存雪崩有两种可能:大量数据在同一个时间失效,比如业务关系强相关的数据要求同时失效/redis宕机。
分析:一般来说,由于更新策略、或者数据热点、缓存服务宕机等原因,可能会导致缓存数据同一时间点大规模不可用,或者都更新。所以,需要我们更新策略要在时间上合适,数据要均匀分享,缓存服务器要做到高可用。
解决办法:更新策略在时间上做到比较均匀。如果数据需要同一时间失效,可以给这批数据加上一些随机值,使得数据不要在同一个时间过期。使用的热数据尽量分散到不同机器上。多台机器做主从复制或者多副本,实现高可用。做好主从部署。实现熔断限流机制,对系统进行负载能力控制。对于非核心功能业务,拒绝其请求,只允许核心功能业务访问数据库获取数据。服务降价:提供默认返回值,或简单提示信息。

13. LRU

双向链表实现

14.什么事堆内存?参数如何设置?

堆内存是指由程序代码自由分配的内存、与栈内存区分
在java中,堆内存主要用于分配对象的存储空间,只要拿到对象引用,所有线程都可以访问堆内存。
-Xmx 指定最大堆内存
-Xms堆内存初始化大小。专用服务器上要保持-Xms和-Xms一致,否则应用刚启动kennel就有好几个fullGC。当两者匹配不一致时,堆内存扩容可能会导致性能抖动。
-Xmn 等价于 -XX:newSize,使用G1垃圾回收器不应该设置该选项,在其他的某些业务场景下可以设置。官方建议 -Xmx的1/2-1/4
-XX:MaxPermSize =size,这是JDK 1.7之前使用的。java 8默认允许的meta空间无限大,次参数无效
-XX:MaxDirectMemorySize = size,系统可以使用的最大堆外内存
-Xss:设置每个线程栈的字节数。例如-Xss1m指定线程1MB,与-XX:ThreadTackSize=1m等价

15 栈和队列使用场景例子

16 Mysql为什么是InnoDB默认引擎

聚集索引是指数据库表行中数据的物理顺序与键值的逻辑(索引)顺序相同。一个表只能有一个聚族索引,因为一个表的物理顺序只有一种情况,所以,对应的聚族索引只能有一个。聚族索引的叶子结点是数据节点,即存储索引,又在叶子结点存储数据。innodb,创建表后生成的文件为: frm创建表的语句,idb:里面的数据+索引文件

17.Mysql索引底层结构为什么使用b+树

  • 哈希虽然能够提供o1的单数据行操作性能,但是对于范围查询和排序却无法很好地支持,最终导致全表扫描;B树能够在非叶子结点中存储数据,但是这也导致查询连续数据时候,可能带来更多的随机IO,而b+树的所有叶节点可以通过指针互相连接,能够减少顺序便利产生的额外随机I/O
    第一,B树一个节点里面存储的是数据,而B+树存储的是索引(地址),所以B树里一个节点存不了多个数据,但是B+树一个节点能存很多索引,B+树叶子结点存所有数据
    二,B+树的叶子节电是数据阶段用了一个链表串联起来,便于范围查找

18. B+树叶子结点链表双向链表

19.MVCC是什么?底层原理是什么?

多版本并发控制,通过读取历史版本的数据,降低并发事务冲突,从而提高并发性能的一种机制。

  • 事务版本号
  • 表的隐藏列
  • undo log
  • read view

20.undo log具体怎么回滚?

  • insert类型的sql,会在undo log中记录下刚insert进来的数据id,当想rollback时候,根据id完成精准删除
  • delete类型的sql,会在undo log中记录下删除前的数据,当回滚时将删除前的数据insert进行
  • update类型的sql,会在undo log中记录下修改前的数据,回滚时候只需要反向update即可
  • 对于select类型的sql,不需要回滚

21.如何查询慢sql产生的原因

  • 分析sql执行计划,思考可能的优化点,是否命中索引等
  • 没有索引或者没有用到索引
  • 内存不足
  • 网络速度慢
  • 是否查询的数据量过大
  • 是否返回了不必要的行或列
  • 锁或者死锁
  • io吞吐量小,形成了瓶颈效应
  • sp_locl,cp_who,活动用户查看,原因是读写竞争资源

22.索引失效的情况有哪些?

  • like以%开头索引无效,以&结尾,索引有效
  • or语句前后没有同时使用索引,当且仅当or语句查询条件前后列均为索引时,索引生效
  • 组合索引,使用的不是第一列索引时候,索引失效,最左匹配规则
  • 数据类型出现隐式转换
  • 使用isnull或者isnotnull
  • not,in,<><!=

23.一个redis实例最多能存放多少keys?List、Set、Sorted Set最多能放多少元素?

2亿5千万个keys,存储极限是系统中可用的内存值

24.Redis数据结构,压缩列表和跳表的区别

  • 压缩列表本质桑就是一个字节数据,是redis为节省内存而设计的一种线性数据结构,可以包含多个元素,每个元素可以是一个字节数组或一个整数
  • 跳跃表是一种有序的数据结构,它通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的。跳跃表支持平均O(logN)、最坏O(N) 复杂度。可以通过顺序操作来批量处理节点

25 redis如何实现主从同步?

  • 全量同步:master服务器会开启一个后台进程用于将redis中数据生成一个rdb文件,与此同时,服务器会缓存所有接收来自客户端的写命令,当后台保存进程处理完毕后,会将该rdb文件传输给slave服务器,而slave服务器会将rdb文件保存在磁盘并通过读取该文件将数据加载到内存,在此之后master服务器会将此期间缓存的命令通过redis传输协议发送给slave服务器,然后slave服务器将这些命令依次作用于自己本地的数据集上最重达到数据的一致性。
  • 增量同步:redis 2.8之后,即使主从链接断掉,也不需要进行全量同步,因为从这个版本开始融入了部分同步的概念。部分同步的实现依赖于master服务器內存中每个slave服务器维护了一份同步日志和同步标识,每个slave服务器在跟master服务器同步时候都会携带自己的同步标识和上次同步的最后位置。
  • redis主从同步策略:主从刚刚连接的时候,进行全量同步,全同步结束后,进行增量同步。当然,如果有需要,slave在任何时候都可以发起全量同步。redis策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步。

26.Spring AOP理解

AOP,面向切面编程,能够将与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,以便减少系统的重复代码,降低模块将耦合度,并有利于未来可拓展性和可维护性

27.Spring bean容器的生命周期是什么样的?

  • Bean容器找到配置文件中spring bean的含义
  • 利用java reflection api创建一个bean的实例
  • 如果涉及一些属性值,利用set方法设置
  • initializingBean 初始化
  • 销毁
举报

相关推荐

0 条评论