这篇博客记录第二次腾讯后台开发社招面试流程,虽然面试流程因人而异,但就我个人感受而言,腾讯的面试从考察内容方面来讲,还是有一定的共通性,这一点,可以从网上众多的面经可以看出,因此,就有了本篇博客,感兴趣的同学可以参考下,文章比较长,请耐心阅读。
先介绍下个人背景,非985,211本科计算机专业,毕业三年,一直从事嵌入式通信领域软件开发。五月上旬从前公司离职,即所谓的裸辞,离职后没有立即找工作。花了20天时间对过往两年的工作进行一番总结和梳理,期间主要分析了Linux内核网络源码。之后用了1.5月学习一门外语,考了一个证书。时间到了七月中旬。这时候,也没有开始找工作。因为,期望去一家大公司,但是,自身实力还不允许。网上看了众多面经(主要来自牛客网,这里感谢牛客网,提供了一个很好的交流平台),大厂对算法与数据结构要求比较高。因此,先从算法与数据结构开始复习,大学的时候学习过这两门课,复习的时候重新将大学课本拿过来学习,《数据结构(C语言版) 严蔚敏》和《算法设计与分析使用教程》。大概花了1.5月,数据结构从基本的数据结构复习,包括线性表、栈和队列、串、数组、树和二叉树、图和排序算法。除了书本的理论复习,还借助leetcode网站进行刷题练习。leetcode我刷了大概100多道题,目前总共有1000多道,刷题无需追求数量,更重要的是能够理解解题思想。这里推荐下力扣的专项练习栏目,我基本上把专项练习全做了,对数据结构的理解帮助真的非常大。除了leetcode,另一项练习就是《剑指offer》,这里也要推荐下,面试的手写算法考察大概有50%的题型出自本书。《剑指offer》可以在牛客网上进行上机练习。在我自己实际的面试过程中,考察的手写算法题基本上来自 leetcode(简单和中等题型) 和《剑指offer》。刷题贵在精不在多,个人感觉,普通算法题基本上是套路题,只要掌握基本数据结构和基本算法,足以应付绝大部分考察。后期我基本上不刷题了,偶尔挑一道简单题保持手感。这里要额外说一下,基本的排序算法一定要掌握,比如冒泡、选择、插入、快排、归并、堆排、桶排序、基数排序。这些排序的时间复杂度和空间复杂度以及区别、使用场景一定要了然于胸,快排、归并、堆排要能够迅速手写出来,到了复习后期,我每天都会练习手写这三个排序,现在基本上保证这三个排序算法每个用时在165秒内写出。排序之所以重要,是因为很多题目都会用到排序,比如海量数据,数据预处理等,不同场景用到的排序也不相同。算法方面,递归和递推用的也比较多,这里需要注意递归有可能存在重复计算问题,此外,dp问题也可以练习下。算法方面还可以参考左神的《直通BAT算法精讲》系列视频。除了基本的数据结构之外,红黑树,平衡树考察的也比较多,这里也要重点关注下。数据结构和算法复习时间1.5月,相当于其它知识所需时间的总和。掌握好数据结构和算法对操作系统、编程语言、计算机网络等也有相当大的帮助。比如,c++ map和set的底层实现基于红黑树,deque的双端队列,list的双向链表。hashmap和hashset的哈希。操作系统里面进程调度算法用到红黑树等。
算法和数据结构复习期间,去腾讯面试了一次。面经参考之前的博客。从结果来看,真是惨不忍睹。算法和数据结构这一块还好,因为有很好复习缘故,问题都能够回答。但是在操作系统、计算机网络、编程语言等角度来看是不及格的水平。腾讯面试考察对软件工程真的是很全面,这一点,在招聘说明里面有详细提到:
具备全面的软件知识结构认知(操作系统、软件工程、设计模式、数据结构、数据库系统、网络安全);
此次面试之后,又陆陆续续参加了其它几个面试,包括江行智能、海康威视。基本上都因为操作系统、计算机网络、编程语言的问题,没有拿到offer。有些公司的技术栈是c++,我只是在大学的时候用过c++,毕业三年一直从事嵌入式c语言的开发,因此,对于c++的问题,无论简单还是困难,都回答不上来,这大概是所有面试失败的共同原因之一。此外,计算机网络是真的没有复习过,没有任何准备,如此,失败也是必然。至于操作系统,很多内容都是知其然不知其所以然,比如进程管理、调度,内存分配等等。通过总结面试失败的原因,以及参考了网上数量众多的面经,归纳了自己需要补足的地方:c++,操作系统,计算机网络以及额外的扩展知识.
c++的复习用了四周,将800多页的《Primer c++》看了三遍,《STL源码剖析》看了大概三遍有余。第一遍看的时候,仅是大概浏览一下全书内容,第二遍是细致的阅读各个章节的内容。第三遍则是依据网上的面经,试题,主要阅读重点章节。在之后的面试过程中,基本上没有被c++的问题难倒过。文后给出我汇总的c++考点。《Primer c++》全书800多页,看了三遍,用了三周左右,这还是以前学习过的,如果要是没学过,不知道需要多久。
操作系统这一块,重点关注进程管理、调度、进程间通信、线程同步、内存管理、虚拟内存等等。复习的方法是先总结网上面经提到的考点,然后结合书本分析。这一块我主要看了《深入理解Linux内核》,《Linux环境编程:从应用到内核》两本书。这里推荐下《Linux环境编程:从应用到内核》这本书,无论从实战还是原理角度来讲,都讲的非常好。操作系统的问题在面试过程中考察的特别多,而且考点也很多。因为考点众多,所以很难面面俱到,所以提醒各位同学千万不要贪多求全,否则,在面试的过程中很难自圆其说。虽说不要贪多求全,但是基本的知识一定要掌握。操作系统的考察点我也有总结出,文后给出。
计算机网络这一块考察的也非常多,看一下腾讯的招聘需求:
精通网络编程、熟悉网络知识,熟悉TCP/IP协议;
计算机网络考察的主要是原理性知识,这里重点关注TCP协议。这一块的复习工作,我主要参考了《计算机网络 谢希仁版》的TCP那一章节,腾讯的TCP知识考察基本上都在这一章,考点包括TCP的三次握手、四次挥手、拥塞控制、nagle算法,karn算法等等。这一块相对来说,只要复习到位,难度不大。
根据几次面试的实际情况,结合网上的面经,我把自己的复习分为6个部分:操作系统、计算机网络、算法和数据结构、编程语言(c++ & golang)、项目经历、扩展知识。
因为项目里面涉及golang开发,因此,偶尔也会被问及相关问题,golang语言我主要复习了golang的GC算法,Go 协程模型,channel实现机制,cgo机制等,学习多了,就会发现,很多知识都是通用的。比如Go的GC,和c++的allocator两级空间配置器、Linux内存的伙伴关系算法,都是基于内存池的理念。
项目经历这一块问的比较多,先说下关于简历的事情,建议大家使用pdf格式保存简历,因为word文档在某些平台会乱码。对于简历上的项目,一定要精通,包括项目的架构、技术难点等等。有些面试官会对你的项目进行刨根问底式的追问,考察你对项目的掌握程度。很多时候,距离我们的项目完成已经过了很长时间,如果面试的时候突然被问,没做任何准备的话,临场不一定能够想起来,那场面就很尴尬,你说项目是自己做的,结果问的时候你又说不清楚...... 总之,事先准备,在面试过程中就可以游刃有余的处理。此外,并不是所有的项目都要写,捡一些重要的,关联度强的项目放上去,让面试官和你有沟通区间。因为搞嵌入式通信的,很多项目涉及驱动开发,但这些内容对于互联网后台开发而言,一般情况下接触不到。前期我的简历有很多涉及驱动开发项目,结果有些面试官看到后一脸茫然。后来我就把关联不强的项目去掉了。
通信行业和互联网行业技术差别还是蛮大的。互联网行业技术更新快,通信行业则着重于稳定,对技术要求不是很高。所以,如果从通信行业跳到互联网行业,还是存在技术脱节的可能。第一次面试腾讯的时候,面试官问我知道那些互联网中间件技术等,当时是一无所知。后来的复习过程中又专门加了一个扩展知识环节,在这一块学习的过程中,我主要学习了一些主流的互联网中间件应用,比如mongodb、redis等等。虽说底层原理不知道,但是毕竟也能够扩展知识面。再说,面试官知道你的了解程度后,也不会深入为难你。这一块主要考察你对技术和行业的关注度。记得谁说过一句话,0和1的差距要大于1和100万的差距。了解一下还是很有用处的。扩展知识我学习了《左手MongoDB,右手Redis : 从入门到商业实战》这本书,按照书中的示例过了一遍,包括搭建开发环境、测试用例等。学过一遍之后,基本上也就了解了其使用。这样在面试的时候,也能够简单描述其功能,不至于听不懂面试官在说什么。
以上就是我复习的六个方面。看牛客网的很多面经,很多面试考察了数据库的知识,包括B树和B-树、索引的实现以及优化等等。很多同学推荐《数据库概论》、《Mysql必知必会》、《高性能 Mysql》这三本书。当时想了下,如果要搞这三本书,大概一个月左右,即便掌握了也很难精通,毕竟自毕业以后,工作中就没有用过数据库。所以关于数据库的部分就没有复习。实际的面试过程中,虽有面试官问数据库,但了解到没有用过之后,就没有继续追问下去。在面试过程中,学习到很重要一点就是扬长避短,不会就承认不会好了,毕竟每个人都会有知识盲区,大家都是人。但是千万不要不会了还在那BB。所谓面试翻车,大概就是这么个场景。
腾讯的面试的流程持续一个多月,如下:
- 20190919周四 第一轮电话面试,技术面。
- 20190925周三 第二轮电话面试,技术面。
- 20191008周二 第三轮和第四轮现场笔试+面试,技术面(原定9月31号,国庆放假推迟一周)。
- 20191017周四 第五轮现场复试,技术面。
- 20191021周一 第六轮HR面。
- 20191023周三 offer call。
第一面流程:
晚八点半,电话面,开始项目介绍,技术难点、实现细节。大概说了20分钟左右,不知道为啥我讲的内容面试官似乎没有理解,可能是项目架构比较复杂,口述不是特别形象,又聊了10分钟,貌似双方谁也没说服谁。开始聊计算机网络、操作系统。内容包括TCP拥塞控制算法、TCP和UDP区别、进程和线程区别等等。都是常规的题目。这一块已经很好的复习过。没问题。时间过去50分钟,面试官总结说我网络协议这一块不错,原理和项目实战比较强,会有下一面。
第二面流程:
距离上一面隔了六天。电话面,大概20分钟左右。内容如下,不分先后:
Q1. 构造函数可以是虚函数吗?
A:不可以。原因有两点:
- 构造对象的时候,必须知道对象的实际类型。而虚函数行为是在运行期间确定实际类型的,在构造对象的时,对象还没有构造成功,编译器无法知道对象的实际类型是该类本身还是其派生类。
- 虚函数的运行依赖于虚函数指针,而虚函数指针在构造函数中进程初始化,让它指向正确的虚函数表,而在对象构造期间,虚函数指针还未构造完成。
Q2. 网络字节序是大端序还是小端序?
A:大端序。
Q3. Linux中如何创建进程以及创建进程后如何区分子进程?
A:使用fork()调用创建子进程,fork()调用返回两个值,大于0的表示父进程,等于0的表示子进程。
Q4. fork创建的子进程继承了父进程哪些内容
A:子进程继承了父进程的地址空间,打开的文件描述符等。
Q5. fork创建的子进程继承了父进程打开的文件描述符,如何让这种继承不发生
A:可以在打开文件的时候,设置FD_CLOSEXEC标志位,如果文件描述符中这个标志位置位,那么调用exec时会自动关闭对应的文件。
Q6. c++虚函数原理
A:虚函数是依赖于虚函数指针实现,每个拥有虚函数的类都有一个虚表,类的对象存在一个虚函数指针,指向实际类型的虚表。虚函数运行的时候,会根据虚函数指针找到正确的虚表,从而执行正确的虚函数。
Q7. c++多态的实现
A:多态分为两种,一种是运行时的多态,一种是编译时的多态。前者称为动态绑定,后者称为静态绑定。动态绑定时由虚函数来实现,静态绑定是由函数重载来实现。
Q8. c++ vector和list的区别?
A:vector是动态数组,会动态进行分配内存,进行扩容操作。list是双向链表。
Q9. 访问vector的迭代器的时候可以删减元素吗?list呢
A:任何对vector的修改都将导致vector的迭代器失效。list因为是双向链表,所以不会失效。
Q10. c++ vector的底层实现原理
A:vector底层是基于动态数组实现。
Q11. c++ map的底层实现
A:map的底层实现是基于红黑树的。
Q12. 红黑树的特点以及常见的二叉平衡树
A:红黑树性能比较高,插入删除时间复杂度保持在logn。和AVL相比,要求不是那么严格,它只要求到叶节点的最长路径不超过最短路径的两倍。相比之下,AVL要求左右子树相差高度不超过一,简单的插入或者删除都会导致树的不平衡需要旋转操作。
(我只说这么多,后来的同学建议说下红黑树的五个特点)
Q13. c++空类的sizeof大小
A:c++空类的大小为1,如果含有虚函数的话,大小为指针的大小。32位系统指针大小是4。c++要求即使是空类,对象也要有存储空间。含有虚函数的空类则是因为对象由虚函数指针。
Q14. 快速排序的时间复杂度
A:快速排序平均时间复杂度位nlogn,最差O(n^2)
Q15. nLogn是排序最好的时间复杂度吗?
A:不是,还有O(n)的算法,比如说基数排序。
Q16. 基数排序的原理以及应用
A:基数排序根据一个数的高低位进行排序。应用不知道,缺点是对负数的处理不太好。
Q17. 介绍负载均衡的应用
A:不知道。
Q18. http协议有用过吗?
A:这个没用过。
Q19. protobuf协议
A:我们公司之前使用的是json协议,没有用过protobuf协议。
Q20. 数据库
A:没用过。
Q21. redis
A:这个是自己学习使用的,生产环境没用过(这里说了下,我用它干嘛的,使用python的flask web框架基于redis的list结构开发一个网络聊天程序)
Q22. 解释线程安全和可重入函数
A:这个是关于多线程访问的吗?可重入函数这个名词听过,但是忘记干啥了,面试官说pass.
(一个可重入函数被称为可重入的,表明该函数被重入之后,不会产生任何不良后果,一个函数被重入,表示这个函数没有执行完成,由于内部原因或外部原因调用,又一次进入该函数执行)
Q23. top的命令cache和buffer区别
A:这个平常没有关注过。(buffer是块设备的读写缓冲区,比如磁盘,cache是文件系统的缓存,常用于文件)
Q24. 常见Linux命令是否用过,比如strace和netstat
A:这个有用过,strace用来跟踪程序的执行,top查看内存,以及tcpdump等进行抓包等等。
Q25. 多个动态库的连接顺序有区别吗,顺序怎么排
A:有顺序的,如果顺序错误的话可能导致编译失败。这里的编译顺序应该是被依赖的库放在后面。(这个我之前工作中遇到这个坑,所以知道。不过当时面试的时候,把顺序忘了)
Q26. 智力题,100本书,两个人轮流拿,每次拿1~5本,你先拿,有没有啥策略可以保证你可以拿到最后一本?
A:这个得承认,智力题不是我的强项,每次遇到的话都要N天才思考明白( ̄_ ̄|||),当时考虑了大概30秒,想着100本这么多,要不先来10本试试,我一本,他一本,我一本.......挣扎了几秒,老实承认,没想到啥好方法。
(此题解法可以是先手拿4本,后续双方每次拿6的倍数,这样可以保证最终可以拿到最后一本)。
=======================================================================================================
第三面流程:
本来约的是9月31号,因为国庆的缘故,延到国庆后。现场面,下午2点来了之后,给了一张试卷,1.5小时完成。如果难度分成5个等级,感觉介于2和3之间。试卷内容保密。总之,考察比较基础也比较全面,C++,操作系统,计算机网络,算法和数据结构。
3点半,两个面试官。对着简历介绍项目,细节,技术难点,架构设计等等。接下来考察软件工程原理。这部分只给出题目。答案我都总结在文末给出的文档里,题目不分先后。
1. Linux互斥锁里面递归锁和非递归锁的使用方式,返回值。
2. Golang Map是否是线程安全,如何设计一个无锁保护的Map(可能答案是使用CAS)。
3. 程序的地址空间分布。
4. 介绍Linux内存管理机制、涉及到的算法。
5. 设计一个内存池。
6. 设计一个定时器
7. 解释时间轮
8. Golang里面CGO原理
9. awk和sed是啥。咋用。
10. TCP粘包怎么解决。
11. 设计线程池。
12. Golang defer语句调用顺序。
13. TIME_WAIT状态有啥用。
14. 画出四次挥手原理图。
15. define和inline区别。
16. 定义常量指针和指针常量。
17. accept是在三次握手哪一次。
18. backlog作用。
闲聊,离职原因,离职几个月这么长时间干啥去了。
=======================================================================================================
第四面面试流程:
大概是总监。
离职原因,离职几个月了干啥去了。
拿着手机看我的博客里有一篇介绍memcpy的标准库函数,让我优化。当时觉得,靠,标准库里的函数咋优化,能优化标准库自己不就优化了,哪轮到我优化???但人家让优化,肯定有优化空间,硬着头皮上。对,就是下面这个函数,看了将近一分钟,咋看都觉得这个函数很完美。觉得一个一个复制已经很好了,还能咋办。问了下,能否给点提示,答曰,不急,慢慢来。又想了一会儿,还是没啥思路,这时候,总监来了一句,“你不觉得一个一个复制有点慢吗”。到了这时候,还是没啥反应,不过既然嫌弃一个一个慢,那两个两个复制可以么?问了下两个两个复制算不算优化,答曰:算。于是想到使用一个short类型复制。后来总监看我有点思路,就提示我说,从汇编角度来优化,包括寄存器大小等等。然后,我使用long long类型来复制,即每次8个。手写了实现,然后总监问我,如果地址不对齐咋办?到这一步,当时没想到地址对齐这个问题,没有答上来,后来想了下,即使没对齐,可以先一个一个复制等对齐了再每次复制8个。
当时对齐问题没啥思路就pass了。感觉面试官水平很高,这道问题的水准也很高。关于优化以及编译的问题,事后查了相关资料,这里推荐两本书:《深入理解计算机系统》、《程序员的自我修养—链接、装载与库》。对于优化的原理、编译器原理讲解的非常好。
void *memmove (void *dest, const void *src, size_t len)
{
char *d = dest;
const char *s = src;
if (d < s)
while (len--)
*d++ = *s++;
else
{
char *lasts = s + (len-1);
char *lastd = d + (len-1);
while (len--)
*lastd-- = *lasts--;
}
return dest;
}
继续做题。
N个M长度数组求交集,求最优解并给出时间复杂度和空间复杂度。我给出的方案是归并、去重、全排序。然后问了下为啥用归并排序,于是介绍快排、归并、堆排各自优缺点和使用场景。然后问有没有更好的解法。想了下,给出了优化方案,仍然是归并,去重,然后hash。然后过。应该有更好的解法,不过目前还没想到,想到的同学教教我。
第三题,c++手写单例模式,《剑指offer》第二题。
因为简历上有些会shell开发,然后给出第四题:
给定一个日志文件,每行包括日期,IP地址,错误码。然后让我使用shell搜索指定日期,指定IP,指定错误的日志出现次数。简单题,grep -rns "date + IP + error" | wc -l
看我的答案之后,在这个题目加了下扩展,除了前述三个内容,还有第四列content,每一行都不一样。马上给了答案:
awk -F"|" "print $1 $2 $3" | grep -rns "date + IP + error" | wc -l。
应该是考察我awk的使用。这里提醒各位同学,自称会shell开发一定要掌握awk和sed的使用。基本上,面试官看到自称会shell必考。
四面就是这样。
整个面试流程持续四个小时。出门已是18点,出门前,面试官告诉我回去等通知。一句话透心凉。觉得自己回答的还不错。虽然称不上卓越。
=======================================================================================================
第五面流程:
距离三面和四面隔了7天,期间没有任何消息,以为凉了。结果来了电话,约复试。
复试的内容没有特殊之处,依旧是基础。内容如下:
1. 介绍前公司产品的功能、市场竞争力、自己负责的部分、产品的软件架构。
简要介绍下前公司的产品、功能、市场竞争力,虽然咱是搞技术的,但是关于产品市场的事情,平常工作中还是多多少少有所关注。此外,就是介绍产品的软件架构图,以及自己负责的模块等等。很多同学遇到类似的问题,会说,自己只负责一个部分,不知道产品的整体架构。这样回答,往往给人的感觉就是很水,搞技术的,不会可以,但是不会可以学啊,虽然,整体架构没涉及过,但是,没吃过猪肉不能没见过猪跑。做了那么久,产品啥架构还不了解,这就有点说不过去了。所以,建议各位同学平常工作过程中,有空的话也从整体的角度思考下产品,万一哪天需要自己搞呢。
2. 路由NAT如何实现。
这一块没有接触过。画了一个映射图,大概描述了一下。
3. 考察结构体字节对齐问题。
4. 概率题,两个红球一个白球,三个盒子。问第二个盒子至少一个红球的概率。
考察概率论。刚开始拿到题,以为需要算法。想了一会儿没啥好方法,略显尴尬的说,使用枚举吧。所谓暴力法。画了一个多叉树的图,一目了然。事后想来,枚举才是最简单的方法。
5. 编程题,字符串去空格。
6. 进程、线程区别。为什么有了多线程还是用多进程。
基本的操作系统原理题。后面的问题只说了进程地址空间有限,不能创建任意多的线程。回来想了下,更好的回答应该是,进程是一个程序实体,多个程序需要多个进程。此外,进程地址空间相互隔离,安全。
7. 平时如何定位问题,core dump怎么产生的。
通常线上问题先复现、再定位。core dump怎么产生不知道。后来查了下,当程序有未处理的信号时,内核会自动生成core dump。能否生成core dump还有ulimit -c的限制。
8. 构造函数调用虚函数可不可以。
不可以。说了下虚函数的作用以及构造函数的调用顺序。后面又问,如果调用会出现啥情况。因为不确定所以说不知道。回来测试了下,是调用被调对象的自己的版本。
9. 算法题:给定电话号码加区号,如何快速查找对应地区。
区号占4位。给了长度10000的数组做hash,O(1)。问有没有办法提高空间利用率,没想到。想到的同学告诉我。然后给了红黑树存储,时间复杂度O(logN)太高。
10. 常用的IDE。
C语言使用source insight,Golang使用liteide。
11. 线程调度问题。
这里解释了下两种调度类以及它们的调度策略,然后是底层的实现原理,后来问调度过程的具体步骤,我记得内核的调度函数是schedule(),具体的操作没有分析过,这里只说了大概,保存寄存器、上下文,然后加载被调进程的上下文、寄存器等等。
12. 不同编译器编译的库能否混用。
没用过,不知道。后来查了下,不同版本的编译器编译出来库不能混用,不过网上的回答也没有解释清楚。觉得可能在问extern "C"问题。
13. 离职原因,离职这么久都干嘛去了。
14. 阅读源码有啥好处?对以前的项目有没有啥改进之处?
15. 有啥问题。
问了下直播业务涉及的终端以及后台开发过程中使用到哪些中间件技术。然后,问了下腾讯的服务器内核啥样子,回答说是定制的T-Linux内核。
整体感觉面试愉快,面试官也在考察知识深度,不会的也没关系。
=======================================================================================================
第六面(HR面)
距离复试三天时间。中午电话。
1. 为啥学些德语。
2. 第一份工作学习到啥。
3. 对腾讯怎么看。
4. 期望薪资以及依据。
5. 当前薪资、福利。
6. 以前是通信的,对互联网怎么看。
7. 部门业务量很多,可能需要加班,你怎么看。
8. 有啥问题想问的。
=======================================================================================================
两天后,给了oc。
=======================================================================================================
腾讯的面试流程大体这样,技术面考察的都是基础,要有深度,不能停留在表面。自己前前后后准备了四个月,从第一次的惨败到后期的从容面对,一步步走下来,收获满满,最终得到想要的结果。