这段时间稍微断更了一段时间,因为我在准备面试。经过两次面试后,有一些比较深刻的认识。对于大厂来说,除了对专业知识考究之外,对算法也尤为看重。
简单的说一下情况,字节已经拿到offer,腾讯所有的面面试已经通过了,也应该有offer了。字节一共4面:3面技术,1面hr;腾讯5次技术面,1次hr面。其中5面是2个面试官上阵。
总的来说腾讯的面试确实强度更高更加持久。字节是分开一次1个小时面试的。而腾讯1、2面是一次一小时,而3面和4面是连续面试一口气高强度的面试2小时,5面则是2个面试官轮流提问。腾讯是持久战稍微脑子不清醒一点就可能出现大错漏。我在4面就是如此,差点出事了。请准备好糖分和水分及时补充,或者洗把脸保持清晰。
面试的过程一般只有1个小时,如何在一个小时内彻底的考究你本人的水平究竟到达那种境界,也是面试官努力的方向。
而面试往往是由两部分构成:
为什么把算法摆在第一点,因为算法在我看来这是大部分没有面试过大厂的朋友可能会忽视的一方面。它的重要程度不比专业知识的考究来的低。
在1-2小时内,如何能快速的看到你编码水平和思维就看这些算法的考究。
因此需要对常见的数据结构比较熟悉,如链表,树,栈,堆。需要知道遇到数组相关的题型可能需要用到如快慢指针等解题思路。还有广度深度优先算法。最后,如果还有更难一点的,会涉及到回溯,动态规划等解题思路。
前面几点都比较好处理,只要在leetcode上做到一定量的题目,都能反应过来。我本人认为我并非是聪明的人,做了300快400道题也仅仅只是摸索出了一些大致的套路。我是完全比不了那些做了100+道题就能灵活掌握算法的大神。
但是经过了系统性的训练,遇到一些常见的算法解题思路可以快速的反应过来。
而动态规划相关的问题,我看来是最难的。关键是需要判断题目是否可以分解成小问题且小问题之间不能互相影响,接着找到动态规划方程,或者是状态转移表。
在听到面试官的算法题后,先不要急着下笔。最好在下笔之前和面试官聊聊你的思路。不同面试官的要求不同,有的面试官,希望算法是原地算法,有的面试官希望时间复杂度降低,有的希望空间复杂度降低。
最好能清晰的表达你的初步思路后,面试官会知道你的算法的方向是否正确,可以一定程度上给予你方向上的指引。
记住就算你做过原题,除非你的方案能保证是从空间和时间复杂度是最优,不然我还是建议面试者多和面试官交流。在交流的过程中,面试官也能明白你的思考过程,从而判断你这个人的编程能力如何。
千万不要小看这个模块的考究,如果说面试专业知识是100分,那么算法题可以占据50分。如果你写不出,或者思路完全偏离了,那就可以说再见了。
在我写文章学习的这5年里面,也有不少的朋友问我的意向,其中不乏有大厂。然而我深知我的算法水平确实不太行,学习的源码水平还不足,很多时候都婉拒了。也就今年和去年,练习算法已有近2个年头,才敢出山试试。
就算是这样的我,算法上的能力评价还是不高,只能说是达到了大厂的合格线,还需要继续加强。
最后,再给两点建议:
一个人光看不练是不行的,一个人瞎琢磨效率偏低。
最好可以买几本书或者课程指导。我是看了辉哥的课程,阅读了极客时间的刘超的数据结构,还阅读了书籍算法4。把基础都补充好后,可以去leetcode中对每一个数据结构专项进行训练。在这些基础上,在做一做剑指offer中经典题目也就差不多了。
网上很多人都在求大厂面试的真题,实际上我看来意义并不大。因为面试官并不会面试你写在简历之外的随意一个问题。一般都是问你简历上的工作成果,以及背后延伸出来的知识点。更多的还是需要自己日常的积累。
当然也有一些老生常谈的基本考点,如Handler,多线程等。
因此,背面试题不是最重要。关键是回顾你的简历上的工作成果以及简历上的知识点,并不断的深挖。
下面是面试情况,以及一些简答。实际上在回答的过程中,可以回答的更加详细,本文只是筛选了部分问题简单介绍了知识点的要点。
字节面试一共4面。字节的面试风格偏向基础的内容,以及简历上知识点的扩展。
1.自我介绍,项目经历,项目上的优化项以及原因
2.为什么使用mmap优化io读写,mmap和传统读写有什么区别?为什么选择它?
简答大意:mmap本质上从内核中 进程中申请了vm_area_struct虚拟内存后,把虚拟内存保存到 file结构体address_space结构体中的i_mmap中。当需要访问这段虚拟地址,就会产生却也中断,通过伙伴系统申请出物理内存绑定。如果是文件映射还会预读取文件内容,之后读取可以命中后续的缓存。项目中也有频繁进行写入,可以快速的同步到内存中。
简答:equal,wait等。
简答: equal 本质上是获取Object的 hashCode。而在hotspot虚拟机中,计算方式在类markOop中,hashCode的计算是获取对象的高16位向右移动16位并且与上掩码。
equal 重写时候,需要按需求处理。一般的,为了让HashMap等需要hashCode计算正确,需要把equal中每一个成员变量。
synchronized 原理。简答:翻译成字节码后,本质上在虚拟机中对应两个字节码 MONITOR_ENTER 以及 MONITOR_EXIT 。通过Monitor进行临界区保护。当执行了MONITOR_ENTER后,本质上就会取出Object 中的LockWord 中的记录锁状态信息。
在Android 虚拟机中,存在3种锁。通过记录thread_id的偏向锁,瘦锁,胖锁。瘦锁是一种乐观锁,本质上就是不断的自旋让渡cpu资源。当64次之后获取不到,则转化为胖锁。胖锁的实现是基于futex进行同步处理的。
volatile原理atomic实现的。简答:优化ui层级,activityidleHandler 处理不重要事件,提前实例化ui到缓存池子,x2c等,展开说。
简答:LeakCanary 本质上是注册监听了四大组件的生命周期,当生命周期销毁时候,通过一个弱引用包裹该Activity/Fragment 等组件对象,并循环检测该对象是否销毁了。解决方案,可以通过ReferenceQueue+虚引用。当GC时候会把这些引用对象添加到引用队列中,接着通过ReferenceDeamon守护线程把数据保存在ReferenceQueue静态变量中,在ReferenceQueue的poll可以拿到。
1.自我介绍,项目经历,项目上的优化项以及优化的原因
2.Rxjava源码原理,以及项目中你是如何将Rxjava流进行复用。
简答:模仿DisposeObserver,当ObservableCreate 调用onSubscribe后就会关联从上流到下流的关系。并通过cas设置到当前执行包的全局变量中。当第二次使用同一个流调用onSubscribe关联再度关联,就会dispose当前的rxjava流。只需要处理这一步骤即可。
详情阅读Rxjava源码解析。
文章:
5.volatile原理
6.synchronize 锁的转化流程。
简答:偏向锁转化瘦锁(owner thread id不一致且没上锁),瘦锁转化胖锁(64次获取不到锁后)。
ReentrantLock 实现。简答:由AQS(AbstractQueuedSynchronizer)实现。ReentrantLock 分为公平锁和非公平锁。AQS本质上是调用acquire 时候为本线程添加到同步队列中,每一个线程代表一个Node,在每个Node会自旋竞争同步队列中的状态。公平锁需要多一个判断,就是保证自己是头节点。
8.ui 优化,首屏渲染时机优化
9.启动优化,与AlphaManager的实现。
10.插桩的原理以及运用。
11.LiveData 和 ViewModel的源码实现
12.x2c 源码实现
13.DNS 原理
14.https的原理
13和14可以阅读(Android网络编程 总览)[https://www.jianshu.com/p/ba60ff3c56e6]
方向:栈的考究。
1.工作软技能的考核,以及团队中的定位
2.如何进行io 优化,指标是什么,优化后的结果以及参数是多少?
方向:可以使用/proc/pid/stat读取cpu的idle,iowait等。使用mmap优化后的结果。
腾讯的面试风格,普遍是基于你的简历上项目经历,往细节往深处问。我是面试因算法失败了一次,后面第二次就成功了。
总结一下2次腾讯面试
1.自我介绍,项目经历,项目上的优化项以及原因
2.ARouter 源码实现,项目中对ARouter的扩展实现详细设计
3.ui 优化,启动优化,首屏展示时机优化
4.volatile 实现
5.Java异常捕获
13.DNS 原理
14.https的原理
6.jni 中JNIEnv 和线程的关系
简答:线程私有,需要JavaVm 重新获取一个jnienv 调用attachThread 方法把线程和新的JNIEnv 绑定起来。
简答:2种,动态和静态。关于整个流程中关键的数据结构之间的关系可以看下面这篇文章的流程图:
JVM引擎执行总结
简答:通过sigaction保存系统默认的处理信号方式,sigaddset 保证一次只关心一种信号,sigaction 设置自定义的信号处理方法。在自定义的信号处理方法中,进行unwind_backtrace 处理,通过_Unwind_GetIP获得native栈信息保存起来,并抛出异常。同时 当前方法地址 和 so的地址获取 相对地址,最后通过addr2line 解析 出是so库中哪一个方法。
1.自我介绍,项目经历,项目上的优化项以及原因
2.ARouter的实现,以及自定义扩展ARouter的实现
3.项目中的io 优化,以及为什么用mmap于io优化
4.mmap的实现
5.mmkv 中 对应 mmap 断电时候的处理机制
6.mmap没调用msync时候,落盘时机。
简答:进程死亡
详情看
因为自己画蛇添足,把每一个节点拷贝了一次,还没有往后迭代,实在是错漏百出就挂了。脑袋还是不够清醒,结果饮恨而归。
1.自我介绍,项目经历,项目上的优化项以及原因
2.ARouter 的实现,以及扩展的实现
3.启动优化,以及ARouter的启动优化方式,ARouter的分区方式
4.Navigation的源码解析
5.基于Navigation 编写路由框架NavigationRouter 的源码实现,以及实现的优点
6.Navigation 实现的路由框架中如何处理Activity和Fragment 嵌套启动的方式
7.class的加载流程
文章:class 文件初识
文章:
最好能回答到epoll和eventfd的层面
mmap的优势和缺点参考答案:横向浅析Small,RePlugin两个插件化框架 中,RePugin是如何通过CP 进行跨进程同步通信
简答:如HashMap,ArrayMap等不支持多线程保护原子性的数据结构。每一次进行put,get操作的时候,都会对modCount 加一。用于记录当前操作次数。一旦看是遍历里面的元素,会不断检查该操作前保存的modCount 是否和之前的一致。不一致则抛出ConcurrentModificationException
ArrayMap 实现简答:ArrayMap 是内存优化的数据结构。核心是由两个数组组成的数据结构。第一个数组记录了key对应的hashCode,这个过程会不断的通过二分法找到hashCode合适的插入位置。获得的index,index左移动1位是key缓存的位置,index左移动1位加1则是value的缓存位置。
ArrayMap中的存在一个静态数组,用来保存大小4/8 开辟过的ArrayMap。如果使用该大小的ArrayMap 则直接使用缓存。
ArrayMap的扩容,当存储的数据大小大于等于hash存储的数组大小则扩容,小于4扩容位4,大于4小于8扩容成8,如果大于8则扩容成原来的1.5倍。
每一次remove 发现是存储的数据是当前容器大小的1/3,则压缩一半。
HashMap 与 ArrayMap比较,两者的优缺点简答:
数据结构上:
内存优化:
性能上:
HashMap 增删的时间复杂度就是O(1)
缓存机制:
扩容机制:
9.handler 的原理
10.handler 是怎么进行postDelay 延时操作。
简答:postDelay 会将延时+当前的时间戳,插入到MessageQueue的合适位置。每一次消费判断时间到达延时的时间点,再进行消费。
简答:通过pollOnce 调用epoll 进行阻塞。
12.volidate 原理
13.当没有添加volidate 修饰属性的时候,数据什么时候从缓存行刷新到主存。
简答:当从synchronized 代码域离开的时候;当线程结束时候;当调用synchronized方法;当第一次访问线程的某个属性。
文章:线程的缓存何时刷新?
腾讯3面和4面是联系到一起的,这里一起说了
1.自我介绍,项目经历,项目上的优化项以及原因
2.mmap 实现原理和io优化
3.View的绘制流程,从 setContentView 解析xml到View的绘制结束。
设计的内容极多和广泛,建议看我写的如下系列文章:
4.硬件渲染流程
5.SurfaceFlinger 在 View绘制流程中扮演的角色
关于5和6两个问题可以详细阅读系列文章: SurfaceFlinger的概述
7.OOM 如何优化,内存爆满是虚拟内存容易先爆掉还是物理内存容易,一口气映射4g的内存是否会发生异常。
8.Bitmap 如何优化避免OOM,为什么放在native中bitmap不容易OOM
9.一个进程最多可以使用多少fd
10.你研究过RN和Flutter,RN的渲染机制和Flutter的渲染机制是如何运作的?他们之间区别是什么?
关于RN和Flutter的文章,之后有机会会和大家分享出来。
目前来说可以去看看gityuan 的博客,里面有详细的介绍了Flutter的通信流程和渲染流程。
而RN的渲染流程倒是很多相关的文章,建议直接结合文章看最新的源码,不是特别的难。
详细可以阅读横向浅析Small,RePlugin两个插件化框架 这篇文章有详细的解析了整个hook的原理和流程。
简答:方向是除余,除法移动int,并保存到栈中。然后推出,生成汉语说法
简答:广度优先算法,遍历8个方向。
本次面试是两个面试官进行考察,考察的东西偏向网络协议。
1.自我介绍,项目经历,项目上的优化项以及自己开源在GitHub上项目的特点。
2.当遇到弱网络时候的优化
简答:1.HttpDns,并解释DNS的原理。2.QUIC协议替换TCP协议,介绍QUIC的原理和TCP的区别。3.接口的适当合并,并结合项目的运用方案1
3.当遇到弱网络时候,网络是如何进行文件重传
4.当遇到弱网络时候,手机连接上了4g,但是没有数据流量时候,如何检测并恢复。
简答:fb的network-connection的库有实现。本质上就是通过一个线程不断的轮训查询TrafficStatus中的4g+wifi数据的状态。核心是调用了下面两个Linux命令:
// stats接口提供各个uid在各个网络接口(wlan0, ppp0等)的流量信息
/proc/net/xt_qtaguid/stats
// iface_stat_fmt接口提供各个接口的汇总流量信息
proc/net/xt_qtaguid/iface_stat_fmt
从专业技能考察可以看到,实际上整个面试过程。腾讯面试的会相对仔细一点,技术广度更加广一点;而字节则更加偏向基础是否扎实。都是从你的简历项目,技术点开始询问,并根据你回答的问题,不断的调整询问的方向,不断的向下挖你的知识点,看能达到什么程度
但是无论如何,你回答的层面最好足够深,从源码层级说起来。有时候面试官的对问题的看法和你的看法有分歧,此时就需要你是否可以从源码的层面上对这些问题有自己的解释。
面试的专业难度没有想象的困难,可以看到大部分的知识都是我在重学系列和往年写的第三方库的分析都有覆盖。
而这些知识我写出来花了3年,实际上学进去就不需要。可以说大部分人都能达到的水平,因此面试的时候只需要沉着冷静的思考,从源码的角度对面试官抛出来问题进行分析,就能比较轻松的解决。
最后有人好奇我去了哪里。应该是去腾讯。
Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/
我有两个Rails模型,即Invoice和Invoice_details。一个Invoice_details属于Invoice,一个Invoice有多个Invoice_details。我无法使用accepts_nested_attributes_forinInvoice通过Invoice模型保存Invoice_details。我收到以下错误:(0.2ms)BEGIN(0.2ms)ROLLBACKCompleted422UnprocessableEntityin25ms(ActiveRecord:4.0ms)ActiveRecord::RecordInvalid(Validationfa
我正在使用Ruby,我正在与一个网络端点通信,该端点在发送消息本身之前需要格式化“header”。header中的第一个字段必须是消息长度,它被定义为网络字节顺序中的2二进制字节消息长度。比如我的消息长度是1024。如何将1024表示为二进制双字节? 最佳答案 Ruby(以及Perl和Python等)中字节整理的标准工具是pack和unpack。ruby的packisinArray.您的长度应该是两个字节长,并且按网络字节顺序排列,这听起来像是n格式说明符的工作:n|Integer|16-bitunsigned,network(bi
HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候
我正在尝试将以下SQL查询转换为ActiveRecord,它正在融化我的大脑。deletefromtablewhereid有什么想法吗?我想做的是限制表中的行数。所以,我想删除少于最近10个条目的所有内容。编辑:通过结合以下几个答案找到了解决方案。Temperature.where('id这给我留下了最新的10个条目。 最佳答案 从您的SQL来看,您似乎想要从表中删除前10条记录。我相信到目前为止的大多数答案都会如此。这里有两个额外的选择:基于MurifoX的版本:Table.where(:id=>Table.order(:id).
我目前正在用Ruby编写一个项目,它使用ActiveRecordgem进行数据库交互,我正在尝试使用ActiveRecord::Base.logger记录所有数据库事件具有以下代码的属性ActiveRecord::Base.logger=Logger.new(File.open('logs/database.log','a'))这适用于迁移等(出于某种原因似乎需要启用日志记录,因为它在禁用时会出现NilClass错误)但是当我尝试运行包含调用ActiveRecord对象的线程守护程序的项目时脚本失败并出现以下错误/System/Library/Frameworks/Ruby.frame
我有一个应用需要发送用户事件邀请。当用户邀请friend(用户)参加事件时,如果尚不存在将用户连接到该事件的新记录,则会创建该记录。我的模型由用户、事件和events_user组成。classEventdefinvite(user_id,*args)user_id.eachdo|u|e=EventsUser.find_or_create_by_event_id_and_user_id(self.id,u)e.save!endendend用法Event.first.invite([1,2,3])我不认为以上是完成我的任务的最有效方法。我设想了一种方法,例如Model.find_or_cr
在许多ruby类之间共享记录器实例的最佳(正确)方法是什么?现在我只是将记录器创建为全局$logger=Logger.new变量,但我觉得有更好的方法可以在不使用全局变量的情况下执行此操作。如果我有以下内容:moduleFooclassAclassBclassC...classZend在所有类之间共享记录器实例的最佳方式是什么?我是以某种方式在Foo模块中声明/创建记录器还是只是使用全局$logger没问题? 最佳答案 在模块中添加常量:moduleFooLogger=Logger.newclassAclassBclassC..
如何在出现异常时指定全局救援,如果您将Sinatra用于API或应用程序,您将如何处理日志记录? 最佳答案 404可以在not_found方法的帮助下处理,例如:not_founddo'Sitedoesnotexist.'end500s可以通过调用带有block的错误方法来处理,例如:errordo"Applicationerror.Plstrylater."end错误的详细信息可以通过request.env中的sinatra.error访问,如下所示:errordo'Anerroroccured:'+request.env['si
例如,假设我有一个名为Products的模型,并且在ProductsController中,我有以下代码用于product_listView以显示已排序的产品。@products=Product.order(params[:order_by])让我们想象一下,在product_listView中,用户可以使用下拉菜单按价格、评级、重量等进行排序。数据库中的产品不会经常更改。我很难理解的是,每次用户选择新的order_by过滤器时,rails是否必须查询,或者rails是否能够以某种方式缓存事件记录以在服务器端重新排序?有没有一种方法可以编写它,以便在用户排序时rails不会重新查询结果