b站-Java后端or数开-日常实习-一/二面

线下面试,没录音,很多题目记不得了

题目

  1. jvm的内存模型?String s = new String("abc")时发生了什么?
  2. jvm的垃圾回收器及使用场景。
  3. 介绍下依赖注入DI
  4. 介绍下HashMap
  5. instanceof实际是怎么完成判断的?
  6. 为什么选择Kafka?为什么能够支持大流量场景?如何保证数据不丢失?
  7. apollo的使用场景和原理
  8. 爬虫后数据清洗的方法有哪些?
  9. redis的使用场景?介绍下zset使用的数据结构?
  10. binlog日志的格式?介绍下redo log和undo log?
  11. 介绍下回表查询

算法

给了两道比较简单的题

53. 最大子序和

136. 只出现一次的数字

复盘

String s = new String("abc")时发生了什么?

首先是去方法区的字符串常量池中寻找"abc"字符串,如果没有,则创建。

在堆中创建一个String对象,指向字符串常量池中的地址。

栈上指向堆中对象的地址。

所以看该字符串常量池中是否存在“abc”,若存在,则只需要在堆中创建一个对象,否则创建两个。

如果对于String a = "abc"?

则无需在堆上创建对象,栈上直接存储指向字符串常量池的地址。

jvm的垃圾回收器及使用场景

为什么需要垃圾回收器?

  1. 释放内存供其他对象使用
  2. 减轻程序员负担,自动管理内存
  3. 减少内存碎片

垃圾回收器及使用场景

注:图中的实线表示新生代垃圾回收器和老年代垃圾回收器的组合使用情况,其中G1和ZGC都是即可新生又可老年。

新生代

从新生代开始说起,Serial是单线程垃圾回收器,其不支持并发,垃圾回收时会停止所有工作线程,且在对大内存进行处理时,但效率效率较低。

由此引出两个改进方向:

  1. 垃圾回收和工作线程并发执行,减少Stop the World(STW)现象
  2. 使用多线程进行垃圾回收,加快对大内存的垃圾回收速度。

针对方向一,专门针对新生代的垃圾回收器均未做调整,这可能是因为年轻代的回收相对较快?引入并发执行可能带来更多的风险?

针对方向二,则引出了Serial的多线程版本:ParNew。单核上与Serial效果一致,多核上效率更高,默认线程数和cpu数量相等。

垃圾回收时,有一个trade off,即停顿时间和吞吐量。有可能面临的问题是:每次的停顿时间减少了,但是停顿次数更多,导致最后的总吞吐量可能更少。根据不同的场景,可以确定目标是max(减少停顿时间, 增大吞吐量)。一般对于web服务,响应用户请求通常需要减少停顿时间,对于长时间的计算任务,交互较少的任务,那可能需要增大吞吐量。

对于新生代的垃圾回收,如果是专注于吞吐量,可以选择Parallel Scavenge,该垃圾回收器的特点是吞吐量优先,且可控。

对于新生代来说,实际垃圾清除时,都是用标记-复制算法,其特点是高效,不会产生内存碎片,缺点就是费内存,但是新生代一般都比较小,所以这么选择也合理。

老年代

和新生代中Serial对应的老年代垃圾回收器是Serial old,也是单线程,优缺点基本一致。

和新生代Parallel Scavenge对应的老年代垃圾回器是Parallel old,优缺点基本一致。

二者均采用标记-整理算法,特点是无内存碎片,但相对效率不高。

在新生代中提到一个改进方向,就是通过工作线程和垃圾线程并发执行,来降低STW时间。老年代中的CMS即从这个角度解决问题,以获取最短停顿时间。

当然这里的并发不是完全并发,是在并发标记和并发清理阶段并发,而在处理标记和重新标记时进行STW,不过这两个阶段很快,最终STW时间很短。

优点上就是低停顿时间,缺点:

  1. 对cpu资源敏感,cpu不足4个时,对用户影响大
  2. 无法处理浮动垃圾,出现Concurrent Mode failure时,会导致full gc,这时候会采用Serial old来进行垃圾收集,Serial old可是一个单线程的垃圾回收器,这次会产生长时间的STW。
  3. 每次垃圾回收阶段,用户线程还在运行,并产生垃圾,所以需要预留空间,不能像其他垃圾回收器那样等老年代满了再回收,这个比较可以通过-XX:CMSInitiatingOccupancyFraction修改。
  4. 使用标记-清除算法,有内存碎片。

老少通吃

G1回收器基于分区的思想,每个小区可以属于新老代。

G1有计划的避免在全区域进行垃圾收集,其根据每个区中垃圾堆积的价值(回收后的空间大小 vs 回收所需要的时间),维护优先队列,来确定收集目标。

每个区维护区域内引用类型与其他区域数据的引用关系,使用Remembered Set,目的是在做GC Roots Tracing时避免扫描全堆。(之前的垃圾回收器在新老之间也要记录)

不同的代所占据的区块数也是动态调整。

整体上使用标记-整理,对于每个小块来说,回收时将其复制到另一小块,是标记-复制。高效且避免了内存碎片。

好处就是STW时间可控(通过参数设置停顿时间不超过N毫秒),由于分区策略,对大内存应用也好使。

至于其如何去解决G1的每个问题,这里就没看了。

ZGC暂时没看。

Kafka高吞吐量的原因

Kafka在普通机械硬盘下也可以达到每秒几百万的处理量。

从以下四个方面考虑其高性能的原因:

  • 磁盘顺序读写:虽然在随机读写下,机械硬盘 < 固态硬盘 << 内存,但是顺序读写时,访问速度差距小了很多。
  • 页缓存:数据首先写入到文件系统的页缓存中,依赖操作系统进行flush时异步刷盘(可以调整producer.type来修改,sync or async),降低磁盘I/O次数。
  • 零拷贝:考虑消费者从kafka消费数据,Kafka将数据发送到网络上的过程
  • 不使用零拷贝的情况,4次传输,CPU参与
  • 使用零拷贝,2次传输,全程DMA控制,缩短时间65%。
  • 批量处理:发送端进行批量压缩和发送,降低网络IO带来的影响。消费者要一条,实际发送了n条,同时通过offset来控制消费进度。

Binlog的日志格式

binlog不同于redo log,undo log,其实在Server层实现的日志。用于备份恢复和主从复制。

如果数据库数据全部被删了,需要通过binlog恢复,redo log因为是循环写,所以数据不全。

Binlog的日志格式分为三种

  • STATEMENT(默认):记录逻辑操作,sql语句。在有uuid,now等动态函数式,可能导致数据不一致。
  • ROW:记录数据最终被修改的样子,但是针对一条update语句,可能会记录n条修改记录,导致binlog过大。
  • MIXED:根据不同情况自动使用STATEMENT和ROW模式。

相比较而言,redo log记录的是物理日志,即在实际的物理地址上进行了什么更新。

instanceof实际是怎么完成判断的?

对 A instanceof B来说,

if A为null: 
  return True
if A == B:
  return True

switch A:
	case 接口类型:
		遍历A实现的接口,若有与B一致的,return True
	case 类类型:
		遍历A的super链直到Object,若有与B一致的,return True
	case 数组类型:
		看B,B如果是类,只能是Object
		B如果是接口,必须是数组实现的接口之一。
		B如果是TC类型的数组,则与A的SC类型的数组,相比,二选一:
			TC和SC是相同的基本类型
			TC和SC都是引用类型,但是可以在运行时强制转换。

参考资料

https://blog.csdn.net/weixin_54232686/article/details/126862579

https://blog.csdn.net/weixin_63020134/article/details/131357852

https://blog.csdn.net/Mr_YanMingXin/article/details/121451254

https://zhuanlan.zhihu.com/p/658756647

https://juejin.cn/post/7103335306103324685

全部评论
m
点赞 回复 分享
发布于 2024-03-04 10:17 贵州
过了吗
点赞 回复 分享
发布于 2024-03-03 14:08 湖南
在哪投的呀
点赞 回复 分享
发布于 2024-02-29 18:48 四川

相关推荐

在牛客上了看了好多佬的面经,确实给自己提供了帮助,再次感谢佬们的面经!我把自己面试的经历也分享给牛友,祝大家都拿到自己想要的offer!#&nbsp;面试复盘##&nbsp;BG双非本+末流211硕+无竞赛+无实习+只有实验室的项目经历##&nbsp;面经###&nbsp;腾讯---软开-java####&nbsp;一面凉经&nbsp;3/18​面试官没有开摄像头,maybe是kpi面,这也是我的第一次面试,整体表现巨差无比,给我留下了深深的打击,觉得自己就是个小废物。​上来经典的自我介绍,然后面试官就问我项目中的难点是什么,也没有追问。接下来就是提问环节​Q1:Mysql和Redis的区别?----&gt;个人怎么用的Redis?​Q2:为什么用kafka?----&gt;kafka重复消费怎么解决?​Q3:进程、线程、协程的区别。(我是菜鸡,没有复习到协程,丢死人了。)​Q4:讲一下对策略的理解​Q5:三道算法题:1、字符串相乘&nbsp;----&gt;2、LRU----&gt;3、乘积最大子数组(基本都是leetcode上的热门题目,但是我没有写出lru,让我深深的知道自己准备的是有多么的不足了,惨痛的经历,我是菜狗啊啊啊啊啊啊啊)​Q6:TCP和UDP的区别,估计是我回答的逻辑不好,就没有追问了​Q7:三次握手以及其中的细节,比如第二次握手失败会发生什么。然后就没有再问了,哭死,面试官很温柔但奈何不了我太菜了。第一次面试的紧张,我在写代码的时候既然在考虑输入输出,在面试官面前改输入输出的函数,第一次给了鹅,我太不珍惜了。###&nbsp;快手---软开-java####&nbsp;一面凉经&nbsp;3/19这次的面试官开了摄像头,我回答不上来的还会给我讲解,告诉我答案,在挂掉之后我也没了自信。经典自我介绍开头+项目中的难点。Q1:索引以及一系列的追问,最后出了一道题select&nbsp;*&nbsp;from&nbsp;t&nbsp;where&nbsp;c&gt;0&nbsp;and&nbsp;b!=1&nbsp;and&nbsp;d=2;问我如何设计索引。答案是联合索引(d,c,b,a)Q2:乐观锁&nbsp;和&nbsp;悲观锁&nbsp;。CAS的实现原理Q3:内存溢出和资源爆炸,讲一下自己经历过的内存溢出和资源爆炸Q4:kafka如何实现顺序消费还有一些关于日常使用的追问Q5:进程的并发执行问题,以及常用的锁。出了个题,讲一件i++如何实现上锁Q6:websocket如何实现通信,要提到sessionQ7:手撕:n个骰子投出为k的概率。这次面试对我打击巨大,面试官说我基础不好,要加强一下自己对基础知识的理解。也彻底没了自信,坐实了自己菜狗的身份。###&nbsp;美团&nbsp;----软开-数开没错。这次岗位跟之前不太一样,我投错了,就是那么的sb,哎,硬着头皮面的。####&nbsp;一面&nbsp;3/27经典的自我介绍,但是没有问项目中的难点。让我讲了将项目具体是做什么的,我巴拉巴拉的介绍了一遍。然后问我学过sql没,我信誓旦旦的说学过,平常经常用,然后一道sql手撕+算法就来了。sql手撕:&nbsp;employee表,找出只有五个直接下属的经理```sqlSELECT&nbsp;e.nameFROM&nbsp;employee&nbsp;eJOIN&nbsp;employee&nbsp;sub&nbsp;ON&nbsp;e.id&nbsp;=&nbsp;sub.managerIdGROUP&nbsp;BY&nbsp;e.id,&nbsp;e.nameHAVING&nbsp;COUNT(*)&nbsp;&gt;=&nbsp;5;```算法手撕:划分字符串,尽可能多的划分,同一字母最多出现在同一个片段中然后问了我听过事务没,我说听过,让我讲一下事务的特性。然后就没然后了,就让我反问了,我都感觉是kpi了,惊喜的是第二天发二面通知了。####&nbsp;二面&nbsp;3/31自我介绍,然后上来就说我们考察代码能力的,直接扔出来一道题“K个一组链表翻转”,秒了。然后他看我做的太快,说再来一道吧,“合并区间”依旧秒了,都是hot100的题。然后他说我能把题背下来也是能力,我说我最近在经常刷题。然后就是八股拷打Q1:虚拟内存是什么&nbsp;虚拟内存的实现&nbsp;虚拟内存遇到空间不够了怎么办,虚拟内存会把资源存在哪里?&nbsp;内存不够了怎么办Q2:tcp&nbsp;如何保证稳定,详细讲一下保证稳定的机制,我讲的是超时重传。syn是什么,有什么用Q3:CAS(没错又问到了cas,这次哥们确实会了)Q4:线程切换Q5:索引,考了我最左匹配原则Q6:聊到了项目,我介绍了项目具体是做什么的,我自己的负责的内容,以及项目中的人员分工Q7:问我为什么选择这个方向,之前没有做过(我不敢说是我选错了,我说出于热爱和好奇,哭死)Q8:聊到了海量数据压缩,我从深度学习和算法的角度分别介绍了一下,没办法撞到了哥们擅长的领域Q8:聊到了AI,讲了讲我是如何使用ai的,以及对ai的看法。ai大势所趋这次面了70分钟左右,最开始我感觉面试官对我是无感的,但是我也尽力的去回答每一个问题,有答的好的答的不好的。面试过程中,面试官说了一句话“你是有自己的理解的。”所以我觉得在面试中还是要尽情的展示一下自己,让面试官感受到你的优点和激情。####&nbsp;4/1面试官通知二面结果,后续有人跟我联系####&nbsp;4/6号hr电话oc####&nbsp;4/9号offer##&nbsp;感悟运气很重要,但是运气是留给有准备的人的。自己没有把握住鹅厂的面试,痛啊,刻在心里的痛啊。快手的打击让我彻底丧失了自信,陷入自我怀疑,从头又看了一遍八股,牛客上刷面经。java后端开发异常的卷,在面完数据开发之后有着深深的感受,大家在选择职位的时候可以酌情考虑吧。我确实卷不动。个人的简历过不了阿里、字节、蚂蚁、饿了么、京东、oppo、vivo、滴滴、作业帮等等的初筛,连面试都约不上,个人条件确实很有限。美团太好了,我是团孝子,我爱喝开水,我爱说实话。##&nbsp;建议1、手撕,hoot100必刷,必刷,必刷,重要的事情说三遍。尤其是动态规划,贪心。面试的时候如果是模板题写不出来基本就凉凉了。2、简历上列出来的东西要能和面试官聊下去,面试官会看着简历问问题。3、面试的时候不要紧张,不用因为某个问题回答不上来就毁自己的状态。而是要尽情的展示自己,从思维上,情绪,性格上等等方面,万一有哪个点打动面试官就成了。4、运气是留给有准备的人的,还是要从自身出发,踏实准备,面的越多就会面的越多。5、合理评估自己准备的情况,java软开卷不动就卷数开,测开,前端,程序员是互通的,不要被语言,前后端限制住了,我们具备的是在这个领域如何快速学习的能力,而不是一门java语言学到死。6、八股是枯燥的,在回答八股的时候要用自己的话说出来,最好结合自己做过的项目,而不是背诵,要给面试官一种错觉,这个问题我在项目中思考过,而不是在八股文里背过。7、面试前在牛客上找对应岗位的面经,把面经里的问题都过一遍,最好再做点问题发散。
查看28道真题和解析
点赞 评论 收藏
分享
评论
9
58
分享

创作者周榜

更多
牛客网
牛客企业服务