美团Java日常实习一面

也是半年前面的,最近复习贴上来

1.自我介绍

2.说说垃圾回收。

3.可达性分析法怎么实现的,根节点有哪些,让你自己实现你怎么做

4.垃圾回收期间发生的动态变化怎么处理,比如一个对象之前是垃圾,现在不是了,会不会回收。

5.哪种gc会发生stop the world

6.说说aqs原理(简历里写的,不写应该不会直接问)。

7.java有哪些引用类型

8.由4引出了ThreadLocalMap的提问,为什么Key是弱引用。

9.ACID是什么,在Innodb怎么实现的。

10.redolog满了怎么办。——文件组循环清除——追问:什么时候清除清除的是哪些数据?

11.是事务执行过程中边写redolog边写数据,还是commit的时候写redolog,先写数据还是先写redolog?

12.说说索引。

13.实习和项目问答

14.算法题:前序中序生成二叉树。

15.研究方向

16.学习或者研究过程中遇到的困难,怎么解决的

17.反问

下面是我自己整理的对上面问题的回答,可能我理解有误,欢迎指出。

2.垃圾回收首先是判断垃圾对象:引用计数法和可达性分析法。

引用计数法:记录对象的被引用数,没引用了就是垃圾。存在自己引用自己或者几个垃圾对象相互引用的情况

可达性分析法:从GCROOT出发,如果能找到对象,即为有用,到不了即为垃圾。

垃圾回收算法:标记清除,标记复制,标记整理。

GCROOT:虚拟机栈、本地方法栈引用对象,方法区中静态属性引用的常量或对象,持有锁的对象。。

可以用三色标记法实现

三种颜色:白色,灰色,黑色。白色表示还未被访问过,灰色表示访问过,但子对象没访问完,黑色表示访问完毕。

过程:所有对象初始是白色,与GCROOT直接可达的改为灰色,加入队列。然后一种从队列里取,标记为黑色,并将其直接可达的白色对象改为灰色,加入队列,如此循环,直到没有灰色对象。

4.stop the world期间自然是不会有这种问题,但垃圾回收器并不会在所有阶段都stw。

以CMS为例,分为四个阶段,可以参照三色标记的过程来理解

1.初始标记:从GCROOT找到能到达的对象,有STW

2.并发标记:无STW,从初始标记的对象出发,遍历整个对象图,完成标记

3.重新标记:STW,修改并发标记期间的产生的变化

4.并发清除

为了减少垃圾回收造成的stw时间,遍历图的过程自然要并发的进行,这时候会产生问题,而重新标记阶段就是为了解决这些问题。虚拟机会记录下并发过程中产生的修改,比如线程清除了一个引用,GC会通过写屏障保存旧引用,确保老对象不会因为断开被错删。这块涉及记忆集,SATB等一些概念,我也囫囵吞枣不管了,一般也不会一直追问到这

5.所有的GC都会,MinorGC,MajorGC,FullGC。

6.AbstractQueuedSynchronizer是抽象队列同步器,是java并发包中提供的构建锁和同步器的基本框架。

首先是它有一个volatile修饰的int型变量state,在ReentrantLock里它表示锁被获取的次数,在Semaphore里它表示剩余的许可数量。一般我们通过cas操作来修改这个变量,cas成功表示获取锁成功,否则失败。

同时,aqs内部维护了一个同步队列,用来存储那些等待获取锁的线程。当线程获取锁失败时,就会把线程引用包装成一个结点放到队列里去。当持有锁的线程释放资源时,会调用release方法,在释放锁之后会把队列里的第一个结点唤醒,被唤醒的线程会去尝试获取锁。

aqs是基于模板方法设计的,它定义了一系列模板方法,如acquire,acquireShared,release,releaseShared等等,我们可以写一个aqs的子类,然后自己实现tryAcquired,tryReleased等几个抽象方法。然后就能实现自定义的同步器。

7.强引用:显示new一个对象就是强引用,一般我们用的都是强引用

软引用:被扫描到并且内存不足就会回收。用于实现内存敏感的缓存:如图片缓存,数据库连接缓存

弱引用:被扫描到就直接回收。可用于避免内存泄漏,案例是ThreadLocal

虚引用:用于监控对象回收过程

8.LocalMap用的是弱引用。

在Thread类里有一个ThreadLocalMap的变量,它是线程私有的空间。它的key为ThreadLocal的弱引用,value为我们自己想存的值。设计成弱引用主要是为了解决内存泄露的问题,尤其是在线程复用的情况下。因为如果是强引用,那么ThreadLocalMap就会一直持有ThreadLocal,导致无法回收。用了弱引用,回收时会将key回收掉,但value不会,但是ThreadLocalMap的get,set,remove方法都会检查key为Null的数据并清除。

9.原子性:uodolog保证

隔离性:MVCC保证

持久性:redolog保证

一致性:以上三个性质都是为了一致性

MVCC是通过ReadView实现的,ReadView是一个逻辑快照,表示某一时刻可见的事务集合。包含了四个重要字段:

m_ids创建时的活跃事务列表;

min_trx_ix_id活跃事务列表里的最小事务id;

max_trx_id创建时应该给下一个事务的id值;

creator_trx_id创建该ReadView的事务的事务id;

然后就能判断某条记录该事务是否可见了。

如果记录的事务id比ReadView中的min_trx_ix_id小,可见;

大于等于max_trx_id则不可见;

在min和max之间且在m_ids里,不可见;

在min和max之间且不在m_ids里,可见;

RW的创建时机:读已提交是每次读都会创建,可重复读是每个事务开启时创建。

10.redolog一般有两个,并且组成1个重做日志文件组。两个文件已循环写的方式来工作。要写满时会阻塞mysql,停下来将buffer pool中的脏页刷新到磁盘。因为redolog的目的是防止数据丢失,写到磁盘就不怕丢了,这些数据在redolog里就可以擦除,就有空间了。

11.这个问题其实还挺难的,面试的时候没想清楚。

事务执行过程中边修改内存数据页(Buffer pool),边写redolog(在redolog buffer);事务提交的时候才进行对redolog持久化。,然后任务事务提交成功。这是默认策略,可以通过参数控制刷盘时机,可以控制提交事务不刷盘,刷盘,以及写到redolog文件(内核空间,还没有没有真正写到磁盘,这时除非操作系统出错或者断电会丢失数据,不会因为Mysql的问题丢失数据了)。

回顾下事务开始到提交过程过三个日志是怎么样的。

BEGIN:开启事务,会分配唯一事务id

执行DML:update ... 修改buffer pool里数据页;生成undolog;写redolog

此时undolog和redolog还在内存里,未持久化;binlog还没写

COMMIT:进入两阶段提交

prepare阶段:redolog打上prepare标记,开始刷盘;

如果此时崩溃,通过prepare标记就知道,丢弃或回滚;

commit阶段:写binlog;binlog刷盘;将redolog状态改为commit;客户端返回‘Commit OK’

为啥先写redolog而不是binlog,因为redolog可以用来恢复,如果写好了redolog没写binlog还能再补上;但如果binlog落盘了,redolog还没有,此时又崩溃了,不但数据丢失,写入磁盘的binlog可能又同步给了从服务器,搞得主从不一致。

且注意,此时只剩Undolog还没落盘。其实已经无所谓了,undolog也是受redolog保护的,只要redolog写到了磁盘,一切都不是问题。undolog也是放在buffer pool中,有个undolog页,什么时候落盘不要紧,由后台线程去弄就行了。

先写redolog保证持久化,而不将数据持久化,这也是常说的WAL(Write-Ahead Logging)。

如果对您有帮助的话欢迎一键三连

全部评论
佬,是不是应该先写redolog再写binlog?
点赞 回复 分享
发布于 今天 10:56 江苏
[羞涩太牛逼了哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈
点赞 回复 分享
发布于 今天 10:44 北京
mark收藏
点赞 回复 分享
发布于 今天 10:43 北京
不懂就问,这些属于八股的知识吗
点赞 回复 分享
发布于 今天 02:59 广东
啥时候投的简历啊哥
点赞 回复 分享
发布于 今天 02:41 浙江
mark收藏
点赞 回复 分享
发布于 今天 02:28 江苏
mark收藏
点赞 回复 分享
发布于 今天 00:03 广东

相关推荐

评论
7
12
分享

创作者周榜

更多
牛客网
牛客企业服务