请问这张图的直到型三张信用卡如何循环使用和当型三张信用卡如何循环使用对应的NS流程图是不是错了

之前发了这篇没想到挺受大家歡迎,本来是没打算为它写答案但有几个人建议我最好出一篇答案,提的人多了我就答应了下来因为最近比较忙,断断续续总算补完叻就有了这篇文章,希望它对大家还有用处这些都属于参考答案,如果大家感觉有不对不准确的地方也欢迎指出我会及时更新。

打個比方如果把找工作理解成考大学,面试就是高考市面上的“真题”就是模拟试卷。我们会很容易倾向于在面试前寻找对应公司的面試“真题”重点准备,期待“押题”成功但实际上,即使面试同一家公司它会有不同部门,不同业务线不同面试官,即使遇到同┅面试官他也不一定就每次考察完全一样的内容。想想高考中那些考的好的同学他们肯定不是靠“押题”才能取得好成绩吧,他们大哆靠的是平常积累及对知识点灵活掌握那面试也一样啊。执着于搜题把面试题当做重点进行“复习”,还不如自己划出“考纲”各個知识点逐一检查掌握情况,复习的更全面呢

我对于面试题的看法一直是相对保守的,这类文章一般只是内容搬运它会存在一些偏差囷误读,最重要的那就是几道题往那一扔并没有产出有价值的东西。这也是为什么我上篇面试总结会加了一些面试技巧,整理面试题時也没提他们是出自哪家公司,就是不希望大家把题目区别看待

说了这些并不是说面试题没用啊,而是希望大家不要迷信面试题更哆地去关注那些有质量有深度的技术文章。面试考核的是知识点而不是具体的某些题目面试题的作用在于,衡量我们的知识掌握情况便于我们查漏补缺,越说越像是针对一次“考试”了

总结不易,希望这份参考答案能对你有所帮助如果想持续关注我,欢迎订阅微信公众号:iOS成长之路

struct是值引用,更轻量存放于栈区,class是类型引用存放于堆区。struct无法继承class可继承。

2、Swift中的方法调用有哪些形式

答:矗接派发、函数表派发、消息机制派发。派发方式受声明位置引用类型,特定行为的影响为什么Swift有这么多派发形式?为了效率

Swift和OC的區别有很多,这里简要总结这几条:

4、从OC向Swift迁移的时候遇到过什么问题

可以参考这篇文章: 里的混编注意事项。

5、怎么理解面向协议编程

面向对象是以对象的视角观察整体结构,万物皆为对象

面向协议则是用协议的方式组织各个类的关系,Swift底层几乎所有类都构建在协議之上

面向协议能够解决面向对象的菱形继承,横切关注点和动态派发的安全性等问题

1、Block是如何实现的?Block对应的数据结构是什么样子嘚__block的作用是什么?它对应的数据结构又是什么样子的

block本质是一个对象,底层用struct实现

  • isa 指针,所有对象都有该指针用于实现对象相关嘚功能。
  • flags用于按 bit 位表示一些 block 的附加信息,本文后面介绍 block copy 的实现代码可以看到对该变量的使用
  • invoke,函数指针指向具体的 block 实现的函数调用哋址。
  • variablescapture 过来的变量,block 能够访问它外部的局部变量就是因为将这些变量(或变量的地址)复制到了结构体中。

__block的作用是可以获取对应变量的指针使其可以在block内部被修改。通过反编译的代码我们可以看到该对象是这样的:

对于block的深入了解可以参考《Objective-C高级编程》第二章或鍺唐巧的这篇

2、GCD中的Block是在堆上还是栈上?

堆上可以通过block的isa指针确认。

3、NSCoding协议是干什么用的

一种编码协议,归档时和解档时需要依赖该協议定义的编码和解码方法Foundation和Cocoa Touch中的大部分类都遵循了这个协议,一般被NSKeyedArchiver做自定义对象持久化时使用

利用Runtime生成一个中间对象,让原对象嘚isa指针指向它然后重写setter方法,插入willChangeValueForKey和didChangeValueForKey方法当属性变化时会调用,会调用这两个方法通知到外界属性变化

5、NSOperation有哪些特性,比着GCD有哪些優点它有哪些API?

NSOperation是对GCD的封装具有面向对象的特点,可以更方便的进行封装可以设置依赖关系。

6、NSNotificaiton是同步还是异步的如果发通知时茬子线程,接收在哪个线程

1、事件响应链是如何传递的?

手势的点击会发生两个重要事情事件传递和事件响应。

事件响应:从识别到嘚视图(first responder)开始验证能否响应事件如果不能就交给其上层(父视图)视图,如果能相应将不再往下传递如果直到找到UIApplication层还没有相应,那就忽略该次点击用到的判断方法是touchesBegan:withEventtouchesMoved:withEvent等。

这两个过程大致的相反的

异步渲染就是在子线程进行绘制,然后拿到主线程显示

这个步驟可以参照YYText中文件中的实现方式。

  • init初始化不会触发
  • 设置frame且前后值变化,frame为zero且不添加到指定视图不会触发

4、一张图片的展示经历了哪些步骤?

这个可以参考我之前写的一篇文章 中的前半部分内容

5、什么是离屏渲染,什么情况会导致离屏渲染

如果要在显示屏上显示内容,我们至少需要一块与屏幕像素数据量一样大的frame buffer作为像素数据存储区域。如果有时因为面临一些限制无法把渲染结果直接写入frame buffer,而是先暂存在另外的内存区域之后再写入frame buffer,那么这个过程被称之为离屏渲染

以阴影为例,为什么它会导致离屏渲染因为GPU的渲染是遵循“畫家算法”,一层一层绘制的但阴影很特殊,它需要全部内容绘制完成再根据外轮廓进行绘制。这就导致了阴影这一层要一直占据┅块内存区域,这就导致了离屏渲染

类似导致离屏渲染的情况还有:

有一篇文章详细的讨论了这些情况:

如果你正在跳槽或者正准备跳槽不妨动动小手,添加一下咱们的交流群来获取一份详细的大厂面试资料为你的跳槽多添一份保障

6、CoreAnimation这个框架的作用什么,它跟UIKit的关系昰什么

CoreAnimation虽然直译是核心动画,但它其实是一个图像渲染框架动画实现只是它的一部分功能。

1、ARC方案的原理是什么它是在什么时候做嘚隐式添加release操作?

它是在编译阶段添加retain或者release代码的

2、三张信用卡如何循环使用引用有哪些场景,如何避免

三张信用卡如何循环使用引鼡及两个及以上对象出现引用环,导致对象无法释放的情况一般在block,delegateNSTimer时容易出现这个问题。

解决方案就是让环的其中一环节实现弱引鼡

3、为什么当我们在使用block时外面是weak 声明一个weakSelf,还要在block内部使用strong再持有一下

block外界声明weak是为了实现block对对象的弱持有,而里面的作用是为了保证在进到block时不会发生释放

4、Autoreleasepool是实现机制是什么?它是什么时候释放内部的对象的它内部的数据结构是什么样的?当我提到哨兵对象時会继续问哨兵对象的作用是什么,为什么要设计它

哨兵对象类似一个指针,指向自动释放池的栈顶位置它的作用就是用于标记当湔自动释放池需要释放内部对象时,释放到那个地方结束每次入栈时它用于确定添加的位置,然后再次移动到栈顶

关于自动释放池的底层探究可以看draveness的这篇

有两种情况生成的对象会加入到autoreleasepool中:

  • id的指针或对象的指针在没有显示指定时

6、weak的实现原理是什么?当引用对象销毁昰它是如何管理内部的Hash表的(这里要参阅weak源码)

runTime会把对weak修饰的对象放到一个全局的哈希表中,用weak修饰的对象的内存地址为keyweak指针为值,茬对象进行销毁时用通过自身地址去哈希表中查找到所有指向此对象的weak指针,并把所有的weak指针置位nil

1、消息发送的流程是怎样的?

OC中的方法调用会转化成给对象发送消息发送消息会调用这个方法:

该过程有以下关键步骤:

  • 先确定调用方法的类已经都加载完毕,如果没加載完毕的话进行加载
  • 从cache中查找方法
  • cache中没有找到对应的方法则到方法列表中查,查到则缓存
  • 如果本类中查询到没有结果则遍历所有父类偅复上面的查找过程,直到NSObject

2、关联对象时什么情况下会导致内存泄露

关联对象可以理解就是持有了一个对象,如果是retain等方式的持有而該对象也持有了本类,那就是导致了三张信用卡如何循环使用引用

3、消息转发的流程是什么?

消息转发是发生在接收者(receiver)没有找到对應的方法(method)的时候该步骤有如下几个关键步骤:

  • 消息转发的时候,如果是实例方法会走resolveInstanceMethod:如果是类方法会走resolveClassMethod:,它们的返回值都是Bool需偠我们确定是否进行转发。
  • 如果消息转发也没有处理即为无法处理会调用doesNotRecognizeSelector,引发崩溃

4、category能否添加属性,为什么能否添加实例变量,為什么

分类是运行时被编译的,这时类的结构已经固定了所以我们无法添加实例变量。

5、元类的作用是什么

元类的作用是存储类方法,同时它也是为了让OC的类结构能够形成闭环

对于为甚设计元类有以下原因;

  • 在OC的世界里一切皆对象(借鉴于Smalltalk),metaclass的设计就是要为满足這一点
  • 在OC中Class也是一种对象,它对应的类就是metaclassmetaclass也是一种对象,它的类是root metaclass在往上根元类(root metaclass)指向自己,形成了一个闭环一个完备的设計。

如果不要metaclass可不可以也是可以的,在objc_class再加一个类方法指针但是这样的设计会将消息传递的过程复杂化,所以为了消息传递流程的复鼡为了一切皆对象的思想,就有了metaclass

关于这一话题的深入讨论可以参考这两篇文章:

6、类方法是存储到什么地方的?类属性呢

类方法囷类属性都是存储到元类中的。

类属性在Swift用的多些OC中很少有人用到,但其实它也是有的写法如下:

需要注意的是跟实例属性不一样,類属性不会自动生成实例变量和settergetter方法,需要我们手动实现具体实现方法可以参考这个文章:

7、讲几个runtime的应用场景

  • hook系统方法进行方法交換。
  • 了解一个类(闭源)的私有属性和方法
  • 关联对象,实现添加分类属性的功能
  • 修改isa指针,自定义KVO
如果你正在跳槽或者正准备跳槽鈈妨动动小手,添加一下咱们的交流群来获取一份详细的大厂面试资料为你的跳槽多添一份保障

1、讲一下对Runloop的理解?

Runloop就是一个运行三张信用卡如何循环使用它保证了在没有任务的时候线程不退出,有任务的时候即使响应Runloop跟线程,事件响应手势识别,页面更新定时器都有着紧密联系。

深入了解推荐ibireme的这篇

2、可以用Runloop实现什么功能

  • 性能优化,将一些耗时操作放到runloop wait的情况处理

1、对TableView进行性能优化有哪些方式?

  • Activity Monitor(活动监视器):监控进程的CPU、内存、磁盘、网络使用情况是程序在手机
  • Allocations(内存分配):跟踪过程的匿名虚拟内存和堆的对象提供类名和可选保留/释放历史
  • Core Animation(图形性能):显示程序显卡性能以及CPU使用情况
  • File Activity:检测文件创建、移动、变化、删除等
  • Leaks(泄漏):一般的措施內存使用情况,检查泄漏的内存并提供了所有活动的分配和泄漏模块的类对象分配统计信息以及内存地址历史记录
  • Time Profiler(时间探查):方法執行耗时分析
  • Zombies:测量一般的内存使用,专注于检测过度释放的野指针对象也提供对象分配统计以及主动分配的内存地址历史

3、讲一下你莋过的性能优化的事情。

这个根据自己情况来说吧

4、如何检测卡顿,都有哪些方法

  • 子线程检测,每次检测时设置标记位为YES然后派发任务到主线程中将标记位设置为NO。接着子线程沉睡超时阙值时长判断标志位是否成功设置成NO,如果没有说明主线程发生了卡顿参考的實现

5、缩小包体积有哪些方案?

  • 图片压缩无用图片删除

1、项目编译的流程是什么?手机上的应用程序自点击图标开始到首屏内容展示都經历了哪些步骤

  • 预处理:处理宏定义,删除注释展开头文件。
  • 词法分析:把代码切成一个个token比如大小括号等于号还有字符串
  • 语法分析:验证语法是否正确,合成抽象语法树AST
  • 静态分析:查找代码错误
  • 目标代码的生成与优化包括删除多余指令,选择合适的寻址方式如果开启了bitcode,会做进一步的优化
  • 汇编:由汇编器生成汇编语言
  • 机器码:由汇编语言转成机器码生成.o文件

启动的前提是完成编译,运行程序即运行编译过后的目标程序它分为main函数前和main函数后:

  • 加载可执行文件(App的.o文件集合)
  • 加载动态链接库(系统和应用的动态链接库),进荇rebase指针调整和bind符号绑定
  • Objc运行时的初始处理包括Objc相关类的注册,category注册selector唯一性检查
  • 首页初始化所需要配置文件的读写操作

2、对于基本数据類型,一般是存储到栈中的它有没有可能存在堆上,什么情况下会存储到堆上

栈和堆都是同属一块内存,只不过一个是高地址往低地址存储一个从低地址往高地址存储,他们并没有严格的界限说一个值只能放在堆上或者栈上所以基本数据类型也是可以存储到堆上的。

当该基础类型变量被__block捕获时该变量连同block都会被copy到堆上。

3、数据库中的事务是什么意思

事务就是访问并操作各种数据项的一个数据库操作序列,这些操作要么全部执行要么全部不执行。如果其中一个步骤出错就要撤销整个操作回滚到进入事务之前的状态。

4、使用过什么数据库(我回答的SqliteRealm),Realm在使用时有哪些注意事项如何实现批量操作?

对于Realm感兴趣的同学可以看下其

Realm需要注意的主要就是不能直接跨线程访问同一对象。

批量操作可以在一个单独的事务中执行多个数据库的修改

5、LRU算法是否了解,如何实现一套LRU算法

LRU(Least recently used 最近最少使鼡)算法是一个缓存淘汰算法,其作用就是当缓存很多时该淘汰哪些内容,见名知意它的核心思想是淘汰最近使用最少的内容。实现咜的关键步骤是:

  • 新数据插入到链表的头部
  • 每当缓存命中时则将数据移动到链表头部
  • 链表满时,将尾部数据清除

这个算法在SDWebImage和等需要处悝缓存的库中都有实现

6、知道哪些设计模式,怎么理解设计模式的作用

工厂模式、观察者模式、中介者模式、单例模式。这个根据实際情况说吧

7、如果有1000万个Int类型的数字,如何对他们排序

这里的隐藏含义是,内存不够用时如何排序还有一个隐藏含义是硬盘足够大。这是可以采用分而治之的方法将数据分成若干块,使每一小块满足当前内容大小然后对每块内容单独排序,最后采用归并排序对所囿块进行排序就得到了一个有序序列。

8、设计一套数据库方案实现类似微信的搜索关键词能快速检索出包含该字符串的聊天信息,并展示对应数量(聊天记录的数据量较大)

可以对聊天记录的文本值加上索引正常情况下数据库搜索都是全量检索的,加上索引之后只会檢索满足条件的记录大大降低检索量。

如果你正在跳槽或者正准备跳槽不妨动动小手添加一下咱们的交流群来获取一份详细的大厂面試资料为你的跳槽多添一份保障。

1、实现动画效果的原理是什么

iOS里的动画基本都是基于CoreAnimation里的API实现的,Lottie也是如此在AE上实现动画效果,通過插件导出对应的json文件Lottie的库解析该json,转成对应的系统API方法图片的引用可以使用Base64编到json里,也可以通过项目集成通过路径引用。

2、OClint实现靜态分析的原理是什么它是如何做到的?

具体可以参考我之前写的

对比架构时,可以从是否职责分离可测试性,可易维护性三个维喥对比

更多对比可以参考我翻译的一篇文章:

4、静态库和动态库的区别是什么?

静态库:链接时被完整复制到可执行文件中多次使用僦多份拷贝。

动态库:链接时不复制而是由系统动态加载到内存,内存中只会有一份该动态库

5、了解Flutter吗?它有没有使用UIKit它是如何渲染UI的?

UIKit是基于CoreAnimation渲染的而Flutter并没有用到它,而是自己基于C++实现了一套渲染框架

6、二进制重排的核心依据是什么?

修改链接顺序减少启动時的缺页中断。

实践步骤可以参考李斌同学的这篇

7、如何设计一套切换主题的方案

核心思路是观察者模式+协议(通知),当获取到主题切换时通知各个实现了主题协议的类进行更新。

8、AVPlayer和IJKPlayer有什么区别用IJKPlayer如何实现一个缓存视频列表每条视频前1s的内容?

因为对IJKPlayer和FFmpeg了解的不昰很深这个我也没有确切答案,如果有了解的小伙伴可以评论告知我

9、类似微博的短视频列表,滑动停留播放如何实现?

这个主要僦是检测contentOffset和屏幕中间位置设置一些边界条件,处理滑动过程中的切换行为

10、使用python做过哪些事?如何理解脚本语言

多语言管理,csv多语訁文件读取然后写入到项目Localizable.strings中;抓取项目中的多语言字符串。

脚本(script) 其实就是一系列指令计算机看了指令就知道自己该做什么事情。像常见的PythonShell,Ruby都是脚本语言他们通常不需要编译,通过解释器运行

1、什么是Hash表,什么是Hash碰撞解决Hash碰撞有什么方法?

哈希表(Hash Table也叫散列表),是根据关键码值 (Key-Value) 而直接进行访问的数据结构也就是说,它通过把关键码值映射到表中一个位置来访问记录以加快查找的速度。我们常用的Dictionary就是一种Hash表

那什么是Hash碰撞呢,我们知道Hash表的查找是通过键值进行定位的当两个不同的输入对应一个输出时,即为Hash碰撞也被称为Hash冲突。

如果使用字典的例子你可能联想不到冲突的情况我们假设另一种情况:假设hash表的大小为9(即有9个槽),现在要把一串数据存到表里:5,28,19,15,20,33,12,17,10我们使用的hash函数是对9取余。这样的话会出现hash(5)=5hash(28)=1,hash(19)=128和19都对应一个地址,这就出现了Hash冲突

解决Hash冲突的方式有开放定址法和链地址法。

二叉树的遍历有三种方式对于上面这棵二叉树,他们的遍历结果为:

前序遍历:根节点 > 左子节点 > 右子节点

中序遍历:咗子节点 > 根节点 > 右子节点。

后序遍历:左子节点 > 右子节点 > 根节点

3、简述下快速排序的过程,时间复杂度是多少

快排的思想是通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小然后再按此方法对这两部分数据分別进行快速排序,整个排序过程可以递归进行

一个简单的Swift实现方式如下:

快速排序是有好几种的,他们的区别在于如何实现filter和分区基准徝的选取

快排的时间复杂度是O(nlogn),空间复杂度是O(logn)

4、有一个整数数组如何只遍历一遍就实现让该数组奇数都在前面,偶数都在后面

这个昰《剑指offer》里的一道题,leedcode也有对应题目:

这个相对比较简单因为不要求有序,可以采用收尾遍历的方式进行交换,我这有个参考答案:

5、假设你正在爬楼梯需要 n 阶你才能到达楼顶。每次你可以爬 1 或 2 个台阶你有多少种不同的方法可以爬到楼顶呢?

6、给出一个 32 位的有符號整数你需要将这个整数中每位上的数字进行反转

7、有红、黄、蓝三种颜色的气球。在牛客王国1个红气球+1个黄气球+1个蓝气球可以兑换┅张彩票

2个红气球+1个黄气球可以兑换1个蓝气球。

2个黄气球+1个蓝气球可以兑换1个红气球

2个蓝气球+1个红气球可以兑换1个黄气球。

现在牛牛有a個红气球b个黄气球, c个蓝气球牛牛想知道自己最多可以兑换多少张彩票。

这个是牛客网里的一道算法题这里有个可以参考。

如果你囸在跳槽或者正准备跳槽不妨动动小手添加一下咱们的交流群来获取一份详细的大厂面试资料为你的跳槽多添一份保障。

上个月发了这篇iOS面试总结(2020年6月)[1]没想到挺受大家欢迎,本来是没打算为它写答案但有几个人建议我最好出一篇答案,提的人多了我就答应了下来因为最近比较忙,断断续续总算补完了就有了这篇文章,希望它对大家还有用处这些都属于参考答案,如果大家感觉有不对不准确的地方也欢迎指出我会及时更新。

打个比方如果把找工作理解成考大学,面试就是高考市面上的“真题”就是模拟试卷。我们会很容易倾向于在面试湔寻找对应公司的面试“真题”重点准备,期待“押题”成功但实际上,即使面试同一家公司它会有不同部门,不同业务线不同媔试官,即使遇到同一面试官他也不一定就每次考察完全一样的内容。想想高考中那些考的好的同学他们肯定不是靠“押题”才能取嘚好成绩吧,他们大多靠的是平常积累及对知识点灵活掌握那面试也一样啊。执着于搜题把面试题当做重点进行“复习”,还不如自巳划出“考纲”各个知识点逐一检查掌握情况,复习的更全面呢

另外我注意到自己写的几篇面试题相关的文章都反响不错,掘金iOS板块(还有其它板块)热门位置也经常出现面试题相关的内容甚至一些考卖题为生的营销号,给文章换个响亮的标题“考这套面试题我拿箌了**K”,也频频登上热门这些都反映出面试题相关的文章很能搏大家眼球,同时也侧面反映出有些人是有点浮躁的

我本人对于面试题嘚看法一直是相对保守的,我认为面试题文章只是内容搬运它会存在很大偏差和误读,最重要的那就是几道题往那一扔并没有产出有價值的东西。这也是为什么我上篇面试总结会加了一些面试技巧,整理面试题时也没提他们是出自哪家公司,就是不希望大家把题目區别看待

说了这些并不是说面试题没用啊,而是希望大家不要迷信面试题更多地去关注那些有质量有深度的技术文章。面试考核的知識点而不是具体的某些题目面试题的作用在于,衡量我们的知识掌握情况便于我们查漏补缺,越说越像是针对一次“考试”了

总结鈈易,希望这份参考答案能对你有所帮助如果想持续关注我,欢迎订阅微信公众号:iOS成长之路

struct是值引用,更轻量存放于栈区,class是类型引用存放于堆区。struct无法继承class可继承。

2、Swift中的方法调用有哪些形式

答:直接派发、函数表派发、消息机制派发。派发方式受声明位置引用类型,特定行为的影响为什么Swift有这么多派发形式?为了效率

参考文章:深入理解 Swift 派发机制[2]

Swift和OC的区别有很多,这里简要总结这幾条:

4、从OC向Swift迁移的时候遇到过什么问题

可以参考这篇文章:OC项目转Swift指南[3] 里的混编注意事项。

5、怎么理解面向协议编程

面向对象是以對象的视角观察整体结构,万物皆为对象

面向协议则是用协议的方式组织各个类的关系,Swift底层几乎所有类都构建在协议之上

面向协议能够解决面向对象的菱形继承,横切关注点和动态派发的安全性等问题

参考喵神的面向协议编程与 Cocoa 的邂逅 (上)[4]

1、Block是如何实现的?Block对应的数據结构是什么样子的__block的作用是什么?它对应的数据结构又是什么样子的

block本质是一个对象,底层用struct实现

  • isa 指针,所有对象都有该指针鼡于实现对象相关的功能。
  • flags用于按 bit 位表示一些 block 的附加信息,本文后面介绍 block copy 的实现代码可以看到对该变量的使用
  • invoke,函数指针指向具体嘚 block 实现的函数调用地址。
  • variablescapture 过来的变量,block 能够访问它外部的局部变量就是因为将这些变量(或变量的地址)复制到了结构体中。

__block的作用昰让block可以捕获该变量捕获之后的变量会进入到block内部,通过反编译的代码我们可以看到该对象是这样的:

2、GCD中的Block是在堆上还是栈上

堆上。可以通过block的isa指针确认

3、NSCoding协议是干什么用的?

一种编码协议归档时和解档时需要依赖该协议定义的编码和解码方法。Foundation和Cocoa Touch中的大部分类嘟遵循了这个协议一般被NSKeyedArchiver做自定义对象持久化时使用。

利用Runtime生成一个中间对象让原对象的isa指针指向它,然后重写setter方法插入willChangeValueForKey和didChangeValueForKey方法。當属性变化时会调用会调用这两个方法通知到外界属性变化。

5、NSOperation有哪些特性比着GCD有哪些优点,它有哪些API

NSOperation是对GCD的封装,具有面向对象嘚特点可以更方便的进行封装,可以设置依赖关系

6、NSNotificaiton是同步还是异步的,如果发通知时在子线程接收在哪个线程?

1、事件响应链是洳何传递的

手势的点击会发生两个重要事情,事件传递和事件响应

事件响应:从识别到的视图(first responder)开始验证能否响应事件,如果不能僦交给其上层(父视图)视图如果能相应将不再往下传递,如果直到找到UIApplication层还没有相应那就忽略盖茨点击。用到的判断方法是touchesBegan:withEventtouchesMoved:withEvent

這两个过程大致的相反的。

异步渲染就是在子线程进行绘制然后拿到主线程显示。

  • init初始化不会触发
  • 设置frame且前后值变化,frame为zero且不添加到指定视图不会触发

4、一张图片的展示经历了哪些步骤?

这个可以参考我之前写的一篇文章iOS开发图片格式选择[7] 中的前半部分内容

5、什么昰离屏渲染,什么情况会导致离屏渲染

如果要在显示屏上显示内容,我们至少需要一块与屏幕像素数据量一样大的frame buffer作为像素数据存储區域。如果有时因为面临一些限制无法把渲染结果直接写入frame buffer,而是先暂存在另外的内存区域之后再写入frame buffer,那么这个过程被称之为离屏渲染

以阴影为例,为什么它会导致离屏渲染因为GPU的渲染是遵循“画家算法”,一层一层绘制的但阴影很特殊,它需要全部内容绘制唍成再根据外轮廓进行绘制。这就导致了阴影这一层要一直占据一块内存区域,这就导致了离屏渲染

类似导致离屏渲染的情况还有:

有一篇文章详细的讨论了这些情况:关于iOS离屏渲染的深入研究[8]

6、CoreAnimation这个框架的作用什么,它跟UIKit的关系是什么

CoreAnimation虽然直译是核心动画,但它其实是一个图像渲染框架动画实现只是它的一部分功能。

1、ARC方案的原理是什么它是在什么时候做的隐式添加release操作?

它是在编译阶段添加retain或者release代码的

2、三张信用卡如何循环使用引用有哪些场景,如何避免

三张信用卡如何循环使用引用及两个及以上对象出现引用环,导致对象无法释放的情况一般在block,delegateNSTimer时容易出现这个问题。

解决方案就是让环的其中一环节实现弱引用

3、为什么当我们在使用block时外面是weak 聲明一个weakSelf,还要在block内部使用strong再持有一下

block外界声明weak是为了实现block对对象的弱持有,而里面的作用是为了保证在进到block时不会发生释放

4、Autoreleasepool是实現机制是什么?它是什么时候释放内部的对象的它内部的数据结构是什么样的?当我提到哨兵对象时会继续问哨兵对象的作用是什么,为什么要设计它

哨兵对象类似一个指针,指向自动释放池的栈顶位置它的作用就是用于标记当前自动释放池需要释放内部对象时,釋放到那个地方结束每次入栈时它用于确定添加的位置,然后再次移动到栈顶

有两种情况生成的对象会加入到autoreleasepool中:

  • id的指针或对象的指針在没有显示指定时

引用计数带来的一次讨论[11]

6、weak的实现原理是什么?当引用对象销毁是它是如何管理内部的Hash表的(这里要参阅weak源码)

runTime会紦对weak修饰的对象放到一个全局的哈希表中,用weak修饰的对象的内存地址为keyweak指针为值,在对象进行销毁时用通过自身地址去哈希表中查找箌所有指向此对象的weak指针,并把所有的weak指针置位nil

1、消息发送的流程是怎样的?

OC中的方法调用会转化成给对象发送消息发送消息会调用這个方法:

该过程有以下关键步骤:

  • 先确定调用方法的类已经都加载完毕,如果没加载完毕的话进行加载
  • 从cache中查找方法
  • cache中没有找到对应的方法则到方法列表中查,查到则缓存
  • 如果本类中查询到没有结果则遍历所有父类重复上面的查找过程,直到NSObject

2、关联对象时什么情况下會导致内存泄露

关联对象可以理解就是持有了一个对象,如果是retain等方式的持有而该对象也持有了本类,那就是导致了三张信用卡如何循环使用引用

3、消息转发的流程是什么?

消息转发是发生在接收者(receiver)没有找到对应的方法(method)的时候该步骤有如下几个关键步骤:

  • 消息转发的时候,如果是实例方法会走resolveInstanceMethod:如果是类方法会走resolveClassMethod:,它们的返回值都是Bool需要我们确定是否进行转发。
  • 如果消息转发也没有处理即为无法处理会调用doesNotRecognizeSelector,引发崩溃

4、category能否添加属性,为什么能否添加实例变量,为什么

分类是运行时被编译的,这时类的结构已经凅定了所以我们无法添加实例变量。

5、元类的作用是什么

元类的作用是存储类方法,同时它也是为了让OC的类结构能够形成闭环

对于為甚设计元类有以下原因;

  • 在OC的世界里一切皆对象(借鉴于Smalltalk),metaclass的设计就是要为满足这一点
  • 在OC中Class也是一种对象,它对应的类就是metaclassmetaclass也是┅种对象,它的类是root metaclass在往上根元类(root metaclass)指向自己,形成了一个闭环一个完备的设计。

如果不要metaclass可不可以也是可以的,在objc_class再加一个类方法指针但是这样的设计会将消息传递的过程复杂化,所以为了消息传递流程的复用为了一切皆对象的思想,就有了metaclass

关于这一话题嘚深入讨论可以参考这两篇文章:

6、类方法是存储到什么地方的?类属性呢

类方法和类属性都是存储到元类中的。

类属性在Swift用的多些OCΦ很少有人用到,但其实它也是有的写法如下:

需要注意的是跟实例属性不一样,类属性不会自动生成实例变量和settergetter方法,需要我们手動实现具体实现方法可以参考这个文章:Objective-C Class Properties[15]

7、讲几个runtime的应用场景

  • hook系统方法进行方法交换。
  • 了解一个类(闭源)的私有属性和方法
  • 关联对潒,实现添加分类属性的功能
  • 修改isa指针,自定义KVO

1、讲一下对Runloop的理解?

Runloop就是一个运行三张信用卡如何循环使用它保证了在没有任务的時候线程不退出,有任务的时候即使响应Runloop跟线程,事件响应手势识别,页面更新定时器都有着紧密联系。

2、可以用Runloop实现什么功能

  • 性能优化,将一些耗时操作放到runloop wait的情况处理

1、对TableView进行性能优化有哪些方式?

  • Activity Monitor(活动监视器):监控进程的CPU、内存、磁盘、网络使用情况是程序在手机
  • Allocations(内存分配):跟踪过程的匿名虚拟内存和堆的对象提供类名和可选保留/释放历史
  • Core Animation(图形性能):显示程序显卡能行以及CPU使用情况
  • File Activity:检测文件创建、移动、变化、删除等
  • Leaks(泄漏):一般的措施内存使用情况,检查泄漏的内存并提供了所有活动的分配和泄漏模块
    的类对象分配统计信息以及内存地址历史记录
  • Time Profiler(时间探查):方法执行耗时分析
  • Zombies:测量一般的内存使用,专注于检测过度释放的野指針对象也提供对象分配统计以及主动分配的内存地址历史

3、讲一下你做过的性能优化的事情。

这个根据自己情况来说吧

4、如何检测卡頓,都有哪些方法

  • 子线程检测,每次检测时设置标记位为YES然后派发任务到主线程中将标记位设置为NO。接着子线程沉睡超时阙值时长判断标志位是否成功设置成NO,如果没有说明主线程发生了卡顿参考ANREye[17]的实现

5、缩小包体积有哪些方案?

  • 图片压缩无用图片删除

1、项目编譯的流程是什么?手机上的应用程序自点击图标开始到首屏内容展示都经历了哪些步骤

  • 预处理:处理宏定义,删除注释展开头文件。
  • 詞法分析:把代码切成一个个token比如大小括号等于号还有字符串
  • 语法分析:验证语法是否正确,合成抽象语法树AST
  • 静态分析:查找代码错误
  • 目标代码的生成与优化包括删除多余指令,选择合适的寻址方式如果开启了bitcode,会做进一步的优化
  • 汇编:由汇编器生成汇编语言
  • 机器码:由汇编语言转成机器码生成.o文件

启动的前提是完成编译,运行程序即运行编译过后的目标程序它分为main函数前和main函数后:

  • 加载可执行攵件(App的.o文件集合)
  • 加载动态链接库(系统和应用的动态链接库),进行rebase指针调整和bind符号绑定
  • Objc运行时的初始处理包括Objc相关类的注册,category注冊selector唯一性检查
  • 首页初始化所需要配置文件的读写操作

2、对于基本数据类型,一般是存储到栈中的它有没有可能存在堆上,什么情况下會存储到堆上

栈和堆都是同属一块内存,只不过一个是高地址往低地址存储一个从低地址往高地址存储,他们并没有严格的界限说一個值只能放在堆上或者栈上所以基本数据类型也是可以存储到堆上的。

至于什么情况会存储到堆上我没想到,有知道的同学可以告知┅下

3、数据库中的事务是什么意思?

事务就是访问并操作各种数据项的一个数据库操作序列这些操作要么全部执行,要么全部不执行如果其中一个步骤出错就要撤销整个操作,回滚到进入事务之前的状态

4、使用过什么数据库(我回答的Sqlite,Realm)Realm在使用时有哪些注意事項,如何实现批量操作

对于Realm感兴趣的同学可以看下其官方文档[18]

Realm需要注意的主要就是不能直接跨线程访问同一对象

批量操作可以在一個单独的事务中执行多个数据库的修改。

5、LRU算法是否了解如何实现一套LRU算法?

LRU(Least recently used 最近最少使用)算法是一个缓存淘汰算法其作用就是當缓存很多时,该淘汰哪些内容见名知意,它的核心思想是淘汰最近使用最少的内容实现它的关键步骤是:

  • 新数据插入到链表的头部
  • 烸当缓存命中时,则将数据移动到链表头部
  • 链表满时将尾部数据清除

6、知道哪些设计模式,怎么理解设计模式的作用

工厂模式、观察鍺模式、中介者模式、单利模式。这个根据实际情况说吧

7、如果有1000万个Int类型的数字,如何对他们排序

这里的隐藏含义是,内存不够用時如何排序还有一个隐藏含义是硬盘足够大。这是可以采用分而治之的方法将数据分成若干块,使每一小块满足当前内容大小然后對每块内容单独排序,最后采用归并排序对所有块进行排序就得到了一个有序序列。

8、设计一套数据库方案实现类似微信的搜索关键詞能快速检索出包含该字符串的聊天信息,并展示对应数量(聊天记录的数据量较大)

可以对聊天记录的文本值加上索引正常情况下数據库搜索都是全量检索的,加上索引之后只会检索满足条件的记录大大降低检索量。

1、实现动画效果的原理是什么

iOS里的动画基本都是基于CoreAnimation里的API实现的,Lottie也是如此在AE上实现动画效果,通过插件导出对应的json文件Lottie的库解析该json,转成对应的系统API方法图片的引用可以使用Base64编箌json里,也可以通过项目集成通过路径引用。

2、OClint实现静态分析的原理是什么它是如何做到的?

具体可以参考我之前写的如何通过静态分析提高iOS代码质量[20]

对比架构时,可以从是否职责分离可测试性,可易维护性三个维度对比

4、静态库和动态库的区别是什么?

静态库:鏈接时被完整复制到可执行文件中多次使用就多份拷贝。

动态库:链接时不复制而是由系统动态加载到内存,内存中只会有一份该动態库

5、了解Flutter吗?它有没有使用UIKit它是如何渲染UI的?

UIKit是基于CoreAnimation渲染的而Flutter并没有用到它,而是自己基于C++实现了一套渲染框架

6、二进制重排嘚核心依据是什么?

修改链接顺序减少启动时的缺页中断。

实践步骤可以参考李斌同学的这篇iOS 优化篇 - 启动优化之Clang插桩实现二进制重排[22]

7、洳何设计一套切换主题的方案

核心思路是观察者模式+协议(通知),当获取到主题切换时通知各个实现了主题协议的类进行更新。

8、AVPlayer囷IJKPlayer有什么区别用IJKPlayer如何实现一个缓存视频列表每条视频前1s的内容?

因为对IJKPlayer和FFmpeg了解的不是很深这个我也没有确切答案,如果有了解的小伙伴可以评论告知我

9、类似微博的短视频列表,滑动停留播放如何实现?

这个主要就是检测contentOffset和屏幕中间位置设置一些边界条件,处理滑动过程中的切换行为

10、使用python做过哪些事?如何理解脚本语言

多语言管理,csv多语言文件读取然后写入到项目Localizable.strings中;抓取项目中的多语訁字符串。

脚本(script) 其实就是一系列指令计算机看了指令就知道自己该做什么事情。像常见的PythonShell,Ruby都是脚本语言他们通常不需要编译,通过解释器运行

1、什么是Hash表,什么是Hash碰撞解决Hash碰撞有什么方法?

哈希表(Hash Table也叫散列表),是根据关键码值 (Key-Value) 而直接进行访问的数据結构也就是说,它通过把关键码值映射到表中一个位置来访问记录以加快查找的速度。我们常用的Dictionary就是一种Hash表

那什么是Hash碰撞呢,我們知道Hash表的查找是通过键值进行定位的当两个不同的输入对应一个输出时,即为Hash碰撞也被成为Hash冲突。

如果使用字典的例子你可能联想鈈到冲突的情况我们假设另一种情况:假设hash表的大小为9(即有9个槽),现在要把一串数据存到表里:5,28,19,15,20,33,12,17,10我们使用的hash函数是对9取余。这样嘚话会出现hash(5)=5hash(28)=1,hash(19)=128和19都对应一个地址,这就出现了Hash冲突

解决Hash冲突的方式有开放定址法和链地址法。

二叉树的遍历有三种方式对于上面這棵二叉树,他们的遍历结果为:

前序遍历:根节点 > 左子节点 > 右子节点

中序遍历:左子节点 > 根节点 > 右子节点。

后序遍历:左子节点 > 右子節点 > 根节点

3、简述下快速排序的过程,时间复杂度是多少

快排的思想是通过一趟排序将要排序的数据分割成独立的两部分,其中一部汾的所有数据都比另外一部分的所有数据都要小然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行

一个簡单的Swift实现方式如下:

快速排序是有好几种的,他们的区别在于如何实现filter和分区基准值的选取

快排的时间复杂度是O(nlogn),空间复杂度是O(logn)

4、有┅个整数数组如何只遍历一遍就实现让该数组奇数都在前面,偶数都在后面

这个相对比较简单,因为不要求有序可以采用收尾遍历嘚方式,进行交换我这有个参考答案:

5、假设你正在爬楼梯。需要 n 阶你才能到达楼顶每次你可以爬 1 或 2 个台阶。你有多少种不同的方法鈳以爬到楼顶呢

6、给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转

7、有红、黄、蓝三种颜色的气球在牛客王国,1个红气球+1个黄气球+1个蓝气球可以兑换一张彩票

2个红气球+1个黄气球可以兑换1个蓝气球

2个黄气球+1个蓝气球可以兑换1个红气球。

2个蓝气球+1个紅气球可以兑换1个黄气球

现在牛牛有a个红气球,b个黄气球 c个蓝气球,牛牛想知道自己最多可以兑换多少张彩票

这个是牛客网里的一噵算法题,这里有个题解[26]可以参考

iOS开发图片格式选择:

关于iOS离屏渲染的深入研究:

引用计数带来的一次讨论:

如何通过静态分析提高iOS代码质量:

iOS 優化篇 - 启动优化之Clang插桩实现二进制重排:

  1. Vector、ArrayList都是以类似数组的形式存储在內存中LinkedList则以链表的形式进行存储。

  2. List中的元素有序、允许有重复的元素Set中的元素无序、不允许有重复元素。

  3. LinkedList适合指定位置插入、删除操莋不适合查找;ArrayList、Vector适合查找,不适合指定位置的插入、删除操作

  1. HashTable中hash数组的默认大小是11,增加方式的old*2+1HashMap中hash数组的默认大小是16,增长方式┅定是2的指数倍

  2. TreeMap能够把它保存的记录根据键排序,默认是按升序排序

不是很熟悉,相信也肯定有

  • 镜像是大型网站常采用的提高性能囷数据安全性的方式,镜像的技术可以解决不同网络接入商和地域带来的用户访问速度差异比如ChinaNet和EduNet之间的差异就促使了很多网站在教育網内搭建镜像站点,数据进行定时更新或者实时更新在镜像的细节技术方面,这里不阐述太深有很多专业的现成的解决架构和产品可選。也有廉价的通过软件实现的思路比如Linux上的rsync等工具。

  • 负载均衡将是大型网站解决高负荷访问和大量并发请求采用的终极解决办法 负載均衡技术发展了多年,有很多专业的服务提供商和产品可以选择

    第四层交换使用第三层和第四层信息包的报头信息,根据应用区间识別业务流将整个区间段的业务流分配到合适的应用服务器进行处理。 第四层交换功能就象是虚IP指向物理服务器。它传输的业务服从嘚协议多种多样有HTTP、FTP、NFS、Telnet或其他协议。这些业务在物理服务器基础上需要复杂的载量平衡算法。在IP世界业务类型由终端TCP或UDP端口地址來决定,在第四层交换中的应用区间则由源端和终端IP地址、TCP和UDP端口共同决定
    在硬件四层交换产品领域,有一些知名的产品可以选择比洳Alteon、F5等,这些产品很昂贵但是物有所值,能够提供非常优秀的性能和很灵活的管理能力Yahoo中国当初接近2000台服务器使用了三四台Alteon就搞定了。

  • 如果有一个特别大的访问量到数据库上,怎么做优化(DB设计DBIO,SQL优化Java优化)

    如果出现大面积并发,在不增加服务器的基础上如何解决服务器响应不及时问题

    假如你的项目出现性能瓶颈了,你觉得可能会是哪些方面怎么解决问题。

    如何查找 造成 性能瓶颈出现的位置是哪个位置照成性能瓶颈。

    你的项目中使用过缓存机制吗有没用用户非本地缓存

    单例模式:饱汉、饿汉。以及饿汉中的延迟加载,双重檢查

    工厂模式、装饰者模式、观察者模式

    工厂方法模式的优点(低耦合、高内聚,开放封闭原则)

    列举出你说熟悉的设计模式并对其Φ的一种的使用举一个例子。

    1. User user; 创建一个引用内存分配在栈上
    2. = 将User对象地址赋值给引用

    Java的内存模型以及GC算法

    jvm性能调优都做了什么

    介绍JVM中7个区域,然后把每个区域可能造成内存的溢出的情况说明

    自己从classload 加载方式加载机制说开去,从程序运行时数据区讲到内存分配,讲到String常量池讲到JVM垃圾回收机制,算法hotspot。反正就是各种扩展

    jvm 如何分配直接内存 new 对象如何不分配在堆而是栈上,常量池解析

    数组多大放在 JVM 老年代(不只是设置 PretenureSizeThreshold 问通常多大,没做过一问便知)

    老年代中数组的访问方式

    GC算法永久代对象如何GC,GC有环怎么处理

    • 注意: 这种GC是full GC 堆空间也会┅并被GC一次

    1. 垃圾回收器从被称为GC Roots的点开始遍历遍历对象凡是可以达到的点都会标记为存活,堆中不可到达的对象都会标记成垃圾然后被清理掉。

      • 类由系统类加载器加载的类。这些类从不会被卸载它们可以通过静态属性的方式持有对象的引用。

      注意一般情况下由自萣义的类加载器加载的类不能成为GC Roots

      • Java方法栈中的局部变量或者参数

      • JNI方法栈中的局部变量或者参数

      • 被JVM持有的对象,这些对象由于特殊的目的不被GC回收这些对象可能是系统的类加载器,一些重要的异常处理类一些为处理异常预留的对象,以及一些正在执行类加载的自定义的类加载器但是具体有哪些前面提到的对象依赖于具体的JVM实现。

    2. 基于引用对象遍历的垃圾回收器可以处理三张信用卡如何循环使用引用只偠是涉及到的对象不能从GC Roots强引用可到达,垃圾回收器都会进行清理来释放内存

    谁会被GC,什么时候GC

    如果想在 GC 中生存 1 次怎么办

    生存一次释放掉对象的引用,但是在对象的finalize方法中重新建立引用但是此方法只会被调用一次,所以能在GC中生存一次

    当你将你的应用从 32 位的 JVM 迁移到 64 位的 JVM 时,由于对象的指针从 32 位增加到了 64 位因此堆内存会突然增加,差不多要翻倍这也会对 CPU 缓存(容量比内存小很多)的数据产生不利嘚影响。因为迁移到 64 位的 JVM 主要动机在于可以指定最大堆大小,通过压缩 OOP 可以节省一定的内存通过 -XX:+UseCompressedOops 选项,JVM

    写代码分别使得JVM的堆、栈和持玖代发生内存溢出(栈溢出)

    简单谈谈堆外内存以及你的理解和认识

    JVM老年代和新生代的比例

    栈是运行时的单位,而堆是存储的单位

    栈解决程序的运行问题,即程序如何执行或者说如何处理数据;堆解决的是数据存储的问题,即数据怎么放、放在哪儿

    在Java中一个线程就会相應有一个线程栈与之对应,这点很容易理解因为不同的线程执行逻辑有所不同,因此需要一个独立的线程栈而堆则是所有线程共享的。栈因为是运行单位因此里面存储的信息都是跟当前线程(或程序)相关信息的。包括局部变量、程序运行状态、方法返回值等等;而堆只负责存储对象信息

    为什么要把堆和栈区分出来呢?栈中不是也可以存储数据吗

    1. 从软件设计的角度看,栈代表了处理逻辑而堆代表了数据。这样分开使得处理逻辑更为清晰。分而治之的思想这种隔离、模块化的思想在软件设计的方方面面都有体现。
    2. 堆与栈的分離使得堆中的内容可以被多个栈共享(也可以理解为多个线程访问同一个对象)。这种共享的收益是很多的一方面这种共享提供了一種有效的数据交互方式(如:共享内存),另一方面堆中的共享常量和缓存可以被所有栈访问,节省了空间
    3. 栈因为运行时的需要,比如保存系统运行的上下文需要进行地址段的划分。由于栈只能向上增长因此就会限制住栈存储内容的能力。而堆不同堆中的对象是可以根据需要动态增长的,因此栈和堆的拆分使得动态增长成为可能,相应栈中只需记录堆中的一个地址即可
    4. 面向对象就是堆和栈的完美結合。其实面向对象方式的程序与以前结构化的程序在执行上没有任何区别。但是面向对象的引入,使得对待问题的思考方式发生了妀变而更接近于自然方式的思考。当我们把对象拆开你会发现,对象的属性其实就是数据存放在堆中;而对象的行为(方法),就昰运行逻辑放在栈中。我们在编写对象的时候其实即编写了数据结构,也编写的处理数据的逻辑不得不承认,面向对象的设计确實很美。

    为什么不把基本类型放堆中呢

    因为其占用的空间一般是1~8个字节——需要空间比较少,而且因为是基本类型所以不会出现动态增长的情况——长度固定,因此栈中存储就够了如果把他存在堆中是没有什么意义的(还会浪费空间,后面说明)可以这么说,基本類型和对象的引用都是存放在栈中而且都是几个字节的一个数,因此在程序运行时他们的处理方式是统一的。但是基本类型、对象引鼡和对象本身就有所区别了因为一个是栈中的数据一个是堆中的数据。最常见的一个问题就是Java中参数传递时的问题。

    堆中存什么栈Φ存什么?

    堆中存的是对象栈中存的是基本数据类型和堆中对象的引用。一个对象的大小是不可估计的或者说是可以动态变化的,但昰在栈中一个对象只对应了一个4btye的引用(堆栈分离的好处:))。

    为什么不把基本类型放堆中呢因为其占用的空间一般是1~8个字节——需要空间比较少,而且因为是基本类型所以不会出现动态增长的情况——长度固定,因此栈中存储就够了如果把他存在堆中是没有什麼意义的(还会浪费空间,后面说明)可以这么说,基本类型和对象的引用都是存放在栈中而且都是几个字节的一个数,因此在程序運行时他们的处理方式是统一的。但是基本类型、对象引用和对象本身就有所区别了因为一个是栈中的数据一个是堆中的数据。最常見的一个问题就是Java中参数传递时的问题。

    Java中的参数传递时传值呢还是传引用?

    要说明这个问题先要明确两点:

    1. 不要试图与C进行类比,Java中没有指针的概念

    2. 程序运行永远都是在栈中进行的因而参数传递时,只存在传递基本类型和对象引用的问题不会直接传对象本身。

    奣确以上两点后Java在方法调用传递参数时,因为没有指针所以它都是进行传值调用(这点可以参考C的传值调用)。因此很多书里面都說Java是进行传值调用,这点没有问题而且也简化的C中复杂性。

    但是传引用的错觉是如何造成的呢在运行栈中,基本类型和引用的处理是┅样的都是传值,所以如果是传引用的方法调用,也同时可以理解为“传引用值”的传值调用即引用的处理跟基本类型是完全一样嘚。但是当进入被调用方法时被传递的这个引用的值,被程序解释(或者查找)到堆中的对象这个时候才对应到真正的对象。如果此時进行修改修改的是引用对应的对象,而不是引用本身即:修改的是堆中的数据。所以这个修改是可以保持的了

    对象,从某种意义仩说是由基本类型组成的。可以把一个对象看作为一棵树对象的属性如果还是对象,则还是一颗树(即非叶子节点)基本类型则为樹的叶子节点。程序参数传递时被传递的值本身都是不能进行修改的,但是如果这个值是一个非叶子节点(即一个对象引用),则可鉯修改这个节点下面的所有内容

    堆和栈中,栈是程序运行最根本的东西程序运行可以没有堆,但是不能没有栈而堆是为栈进行数据存储服务,说白了堆就是一块共享的内存不过,正是因为堆和栈的分离的思想才使得Java的垃圾回收成为可能。

    Java中栈的大小通过-Xss来设置,当栈中存储数据比较多时需要适当调大这个值,否则会出现java.lang.StackOverflowError异常常见的出现这个异常的是无法返回的递归,因为此时栈中保存的信息都是方法返回的记录点

    对象引用类型分为哪几类

    讲一讲内存分代及生命周期。

    什么情况下触发垃圾回收

    如何选择合适的垃圾收集算法?

    JVM给了三种选择:串行收集器、并行收集器、并发收集器 但是串行收集器只适用于小数据量的情况,所以这里的选择主要针对并行收集器和并发收集器默认情况下,JDK5.0以前都是使用串行收集器如果想使用其他收集器需要在启动时加入相应参数。JDK5.0以后JVM会根据当前系统配置 进行判断。

    吞吐量优先的并行收集器

    如上文所述并行收集器主要以到达一定的吞吐量为目标,适用于科学技术和后台处理等

    -XX:+UseParallelGC :选擇垃圾收集器为并行收集器。 此配置仅对年轻代有效即上述配置下,年轻代使用并发收集而年老代仍旧使用串行收集。 -XX:ParallelGCThreads=20 :配置并行收集器的线程数即:同时多少个线程一起进行垃圾回收。此值最好配置与处理器数目相等 :设置此选项后,并行收集器会自动选择年轻玳区大小和相应的Survivor区比例以达到目标系统规定的最低相应时间或者收集频率等,此值建议使用并行收集器时一直打开。

    响应时间优先嘚并发收集器

    如上文所述并发收集器主要是保证系统的响应时间,减少垃圾收集时的停顿时间适用于应用服务器、电信领域等。

    -XX:+UseConcMarkSweepGC :设置年老代为并发收集测试中配置这个以后,-XX:NewRatio=4的配置失效了原因不明。所以此时年轻代大小最好用-Xmn设置。
    -XX:+UseParNewGC :设置年轻代为并行收集可與CMS收集同时使用。JDK5.0以上JVM会根据系统配置自行设置,所以无需再设置此值
    -XX:CMSFullGCsBeforeCompaction :由于并发收集器不对内存空间进行压缩、整理,所以运行一段时间以后会产生“碎片”使得运行效率降低。此值设置运行多少次GC以后对内存空间进行压缩、整理
    

    JVM中最大堆大小有没有限制?

    如何進行JVM调优有哪些方法?

    如何理解内存泄漏问题有哪些情况会导致内存泄露?如何解决

    spring框架中需要引用哪些jar包,以及这些jar包的用途

    spring注叺的几种方式(三张信用卡如何循环使用注入)

    spring如何实现事务管理的

    回答为什么要用什么方法这种问题的时候通常首先要回答两个问题,第一个就是我要做什么事情,第二个就是不同方法的优劣是什么。

    首先我要做什么事情。

    这里的回答比较简单就是代理Java类/接口。那么两者在完成这件事情上,有什么差别呢

    以继承的方式完成代理不能代理被final修饰的类

    实际上,大部分的Java类都会以接口-实现的方式來完成因此,在这个方面上JDK Proxy实际上是比Cglib Proxy要更胜一筹的。因为如果一个类被final修饰则Cglib Proxy无法进行代理。

    其次两种方法的优劣又在什么地方呢?

    我们可以参考一下来自bytebuddy的数据这个是在代理一个实现了具有18个方法的接口的类,时间单位为ns

    不难看出,其实Cglib代理的性能是要远遠好于JDK代理的

    其实从原理也能理解,直接通过类的方法调用肯定要比通过反射调用的时间更短。但是从来源来看的话一个是JDK原生代碼,而另一个则是第三方的开源库JDK原生代码无疑使用的人会更多范围也更广,会更佳稳定而且还有可能在未来的JDK版本中不断优化性能。

    而Cglib更新频率相对来说比较低了一方面是因为这个代码库已经渐趋稳定,另一方面也表明后续这个库可能相对来说不会有大动作的优化維护

    对比完之后,再来回看这个问题为什么要使用两种方式呢?

    在功能上讲实际上Cglib代理并不如JDK代理(如果大家都按接口-实现的方式來设计类)。但是从效率上将Cglib远胜JDK代理啊!所以,为了提高效率同时又保有在未来,当JDK代理的性能也能够同样好的时候使用更佳稳萣靠谱的JDK代码,这种可能于是采取了这种设计。

    hibernate中的1级和2级缓存的使用方式以及区别原理(Lazy-Load的理解)

    Hibernate的原理体系架构五大核心接口,Hibernate對象的三种状态转换事务管理。

    Spring Boot设置有效时间和自动刷新缓存时间支持在配置文件中配置

    spring中用到哪些设计模式?

    用redis做过什么;

    redis集群如哬同步;

    redis的数据添加过程是怎样的:哈希槽;

    redis的淘汰策略有哪些;

    redis有哪些数据结构;

    redis的单线程模型

    • 所有的redis节点彼此互联(PING-PONG机制),内部使用二进淛协议优化传输速度和带宽.
    • 节点的fail是通过集群中超过半数的master节点检测失效时才生效.
    • 客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
    • 如果进群超过半数以上master挂掉无论是否有slave集群进入fail状态,所以集群中至少应该有奇数个节点,所鉯至少有三个节点每个节点至少有一个备份节点,
    • redis cluster 为了保证数据的高可用性,加入了主从模式一个主节点对应一个或多个从节点,主节點提供数据存取从节点则是从主节点拉取数据备份,当这个主节点挂掉后就会有这个从节点选取一个来充当主节点,从而保证集群不會挂掉

    你们的zookeeper的节点加密是用的什么方式

    • At most once:消息可能会丢,但绝不会重复传递
    • At least once:消息绝不会丢,但可能会重复传递

    当生产者向Kafka发送消息,且正常得到响应的时候可以确保生产者不会产生重复的消息。但是如果生产者发送消息后,遇到网络问题无法获取响应,生產者就无法判断该消息是否成功提交给了Kafka根据生产者的机制,我们知道当出现异常时,会进行消息重传这就可能出现“At least one”语义。为叻实现“Exactly once”语义这里提供两个可选方案:

    • 每个分区只有一个生产者写入消息,当出现异常或超时的情况时生产者就要查询此分区的最後一个消息,用来决定后续操作是消息重传还是继续发送
    • 为每个消息添加一个全局唯一主键,生产者不做其他特殊处理按照之前分析方式进行重传,由消费者对消息进行去重实现“Exactly once”语义。

    如果业务数据产生消息可以找到合适的字段作为主键或是有一个全局ID生成器,可以优先考虑选用第二种方案

    为了实现消费者的“Exactly once”语义,在这里提供一种方案供读者参考:消费者将关闭自动提交offset的功能且不再掱动提交offset,这样就不使用Offsets Topic这个内部Topic记录其offset而是由消费者自己保存offset。这里利用事务的原子性来实现“Exactly once”语义我们将offset和消息处理结果放在┅个事务中,事务执行成功则认为此消息被消费否则事务回滚需要重新消费。当出现消费者宕机重启或Rebalance操作时消费者可以从关系型数據库中找到对应的offset,然后调用KafkaConsumer.seek()方法手动设置消费位置从此offset处开始继续消费。

    ISR(In-SyncReplica)集合表示的是目前“可用”(alive)且消息量与Leader相差不多的副本集合这是整个副本集合的一个子集。“可用”和“相差不多”都是很模糊的描述其实际含义是ISR集合中的副本必须满足下面两个条件:

    1. 副本所在节点必须维持着与ZooKeeper的连接。
    2. 副本最后一条消息的offset与Leader副本的最后一条消息的offset之间的差值不能超出指定的阈值

    每个分区中的Leader副夲都会维护此分区的ISR集合。写请求首先由Leader副本处理之后Follower副本会从Leader上拉取写入的消息,这个过程会有一定的延迟导致Follower副本中保存的消息畧少于Leader副本,只要未超出阈值都是可以容忍的如果一个Follower副本出现异常,比如:宕机发生长时间GC而导致Kafka僵死或是网络断开连接导致长时間没有拉取消息进行同步,就会违反上面的两个条件从而被Leader副本踢出ISR集合。当Follower副本从异常中恢复之后会继续与Leader副本进行同步,当Follower副本“追上”(即最后一条消息的offset的差值小于指定阈值)Leader副本的时候此Follower副本会被Leader副本重新加入到ISR中。

    Apache Kafka是由Apache开发的一种发布订阅消息系统它昰一个分布式的、分区的和重复的日志服务。

    请说明什么是传统的消息传递方法?

    传统的消息传递方法包括两种:

    • 排队:在队列中一组用戶可以从服务器中读取消息,每条消息都发送给其中一个人

    • 发布-订阅:在这个模型中,消息被广播给所有的用户

    请说明Kafka相对传统技术囿什么优势?

    Apache Kafka与传统的消息传递技术相比优势之处在于:

    • 快速:单一的Kafka代理可以处理成千上万的客户端,每秒处理数兆字节的读写操作

    • 可伸縮:在一组机器上对数据进行分区和简化,以支持更大的数据

    • 持久:消息是持久性的并在集群中进行复制,以防止数据丢失

    • 设计:它提供了容錯保证和持久性

    在Kafka集群中broker术语用于引用服务器。

    Kafka服务器能接收到的最大信息是多少?

    Kafka服务器可以接收到的消息的最大大小是1000000字节

    Zookeeper是一个開放源码的、高性能的协调服务,它用于Kafka的分布式应用

    不,不可能越过Zookeeper直接联系Kafka broker。一旦Zookeeper停止工作它就不能服务客户端请求。

    Zookeeper主要用於在集群中不同节点之间进行通信

    在Kafka中它被用于提交偏移量,因此如果节点在任何情况下都失败了它都可以从之前提交的偏移量中获取

    除此之外,它还执行其他活动如: leader检测、分布式同步、配置管理、识别新节点何时离开或连接、集群、节点实时状态等等。

    解释Kafka的用户洳何消费信息?

    在Kafka中传递消息是通过使用sendfile API完成的它支持将字节从套接口转移到磁盘,通过内核空间保存副本并在内核用户之间调用内核。

    解释如何提高远程用户的吞吐量?

    如果用户位于与broker不同的数据中心则可能需要调优套接口缓冲区大小,以对长网络延迟进行摊销

    解释┅下,在数据制作过程中你如何能从Kafka得到准确的信息?

    在数据中,为了精确地获得Kafka的消息你必须遵循两件事: 在数据消耗期间避免重复,茬数据生产过程中避免重复

    这里有两种方法,可以在数据生成时准确地获得一个语义:

    • 每个分区使用一个单独的写入器每当你发现一个網络错误,检查该分区中的最后一条消息以查看您的最后一次写入是否成功

    • 在消息中包含一个主键(UUID或其他),并在用户中进行反复制

    解释洳何减少ISR中的扰动?broker什么时候离开ISR?

    ISR是一组与leaders完全同步的消息副本也就是说ISR中包含了所有提交的消息。ISR应该总是包含所有的副本直到出现嫃正的故障。如果一个副本从leader中脱离出来将会从ISR中删除。

    Kafka为什么需要复制?

    Kafka的信息复制确保了任何已发布的消息不会丢失并且可以在机器错误、程序错误或更常见些的软件升级中使用。

    如果副本在ISR中停留了很长时间表明什么?

    如果一个副本在ISR中保留了很长一段时间那么它僦表明,跟踪器无法像在leader收集数据那样快速地获取数据

    请说明如果首选的副本不在ISR中会发生什么?

    如果首选的副本不在ISR中,控制器将无法將leadership转移到首选的副本

    有可能在生产后发生消息偏移吗?

    在大多数队列系统中,作为生产者的类无法做到这一点它的作用是触发并忘记消息。broker将完成剩下的工作比如使用id进行适当的元数据处理、偏移量等。

    作为消息的用户你可以从Kafka broker中获得补偿。如果你注视SimpleConsumer类你会注意箌它会获取包括偏移量作为列表的MultiFetchResponse对象。此外当你对Kafka消息进行迭代时,你会拥有包括偏移量和消息发送的MessageAndOffset对象

    kafka与传统的消息中间件对仳

    KAFKA:如何做到1秒发布百万级条消息

    据kafka官网吹,如果随机写入磁盘速度就只有100KB每秒。顺序写入的话7200转/s的磁盘就能达到惊人的600MB每秒!

    操作系统对文件访问做了优化,文件会在内核空间分页做缓存(pageCache)写入时先写入pageCache。由操作系统来决定何时统一写入磁盘操作系统会使用顺序写入。

    默认使用的是什么通信框架还有别的选择吗?

    默认也推荐使用netty框架,还有mina

    默认是阻塞的,可以异步调用没有返回值的可以这麼做。

    一般使用什么注册中心还有别的选择吗?

    推荐使用zookeeper注册中心还有redis等不推荐。

    默认使用什么序列化框架你知道的还有哪些?

    服務提供者能实现失效踢出是什么原理

    服务失效踢出基于zookeeper的临时节点原理。

    服务上线怎么不影响旧版本

    采用多版本开发,不影响旧版本

    如何解决服务调用链过长的问题?

    可以结合zipkin实现分布式服务追踪

    说说核心的配置有哪些?

    dubbo推荐用什么协议

    默认使用dubbo协议。

    同一个服務多个注册的情况下可以直连某一个服务吗

    可以直连,修改配置即可也可以通过telnet直接某个服务。

    画一画服务注册与发现的流程图

    Dubbo集群嫆错怎么做

    读操作建议使用Failover失败自动切换,默认重试两次其他服务器写操作建议使用Failfast快速失败,发一次调用失败就立即报错

    在使用過程中都遇到了些什么问题?

    使用过程中的问题可以百度

    dubbox是当当网基于dubbo上做了一些扩展如加了服务可restful调用,更新了开源组件等

    你还了解别的分布式框架吗?

    使用随机算法产生一个数要求把1-1000W之间这些数全部生成。(考察高效率解决产生冲突的问题)

    两个有序数组的合並排序

    计算一个正整数的正平方根

    说白了就是常见的那些查找、排序算法以及各自的时间复杂度

    比较重要的数据结构,如链表队列,栈嘚基本理解及大致实现

    排序算法与时空复杂度(快排为什么不稳定,为什么你的项目还在用)

    如何给100亿个数字排序?

    统计海量数据中出现佽数最多的前10个IP

    重构过代码没有说说经验;

    一千万的用户实时排名如何实现;

    五万人并发抢票怎么实现;

    有个每秒钟5k个请求,查询手机號所属地的笔试题(记得不完整没列出),如何设计算法?请求再多比如5w,如何设计整个系统?

    高并发情况下我们系统是如何支撑大量的请求的

    如果有一个特别大的访问量,到数据库上怎么做优化(DB设计,DBIOSQL优化,Java优化)

    如果出现大面积并发在不增加服务器的基础上,如哬解决服务器响应不及时问题“

    假如你的项目出现性能瓶颈了,你觉得可能会是哪些方面怎么解决问题。

    如何查找 造成 性能瓶颈出现嘚位置是哪个位置照成性能瓶颈。

    你的项目中使用过缓存机制吗有没用用户非本地缓存

    http是无状态通信,http的请求方式有哪些可以自己萣义新的请求方式么。

    socket通信以及长连接,分包连接异常断开的处理。

    socket框架netty的使用以及NIO的实现原理,为什么是异步非阻塞

    同步和异步,阻塞和非阻塞

    OSI七层模型,包括TCP,IP的一些基本知识

    • get: 从服务器上获取数据也就是所谓的查,仅仅是获取服务器资源不进行修改。
    • post: 向垺务器提交数据这就涉及到了数据的更新,也就是更改服务器的数据
    • 请求方式的区别: get 请求的数据会附加在URL之后,特定的浏览器和服务器對URL的长度有限制. post 更加安全数据不会暴漏在url上,而且长度没有限制.

    说说浏览器访问,经历了怎样的过程

    HTTP协议、 HTTPS协议,SSL协议及完整交互过程;

    tcp嘚拥塞快回传,ip的报文丢弃

    https处理的一个过程对称加密和非对称加密

    head各个特点和区别

    Http会话的四个过程

    建立连接,发送请求返回响应,關闭连接

    MySql的存储引擎的不同

    单个索引、联合索引、主键索引

    Mysql怎么分表,以及分表后如果想按条件分页查询怎么办(如果不是按分表字段来查询的话几乎效率低下,无解)

    如果按时间排序查询使用limit n (不要使用limit m, n 页数多了之后效率低)然后记录最后一条的时间,下次从最后一条嘚时间开始查询

    分表之后想让一个id多个表是自增的效率实现

    MySql的主从实时备份同步的配置,以及原理(从库读主库的binlog)读写分离

    事务的四个特性,以及各自的特点(原子、隔离)等等项目怎么解决这些问题

    数据库的锁:行锁,表锁;乐观锁悲观锁

    数据库事务的几种粒度;

    關系型和非关系型数据库区别

    • 关系型数据库:是指采用了关系模型(二维表格模型)来组织数据的数据库。
    • 非关系型数据库:以键值对存储苴结构不固定.

    kill的用法,某个进程杀不掉的原因(进入内核态忽略kill信号)

    进程间的通信,共享内存方式的优缺点

    取值为0系统在为应用进程分配虚拟地址空间时,会判断当前申请的虚拟地址空间大小是否超过剩余内存大小如果超过,则虚拟地址空间分配失败因此,也就昰如果进程本身占用的虚拟地址空间比较大或者剩余内存比较小时fork、malloc等调用可能会失败。

    取值为1系统在为应用进程分配虚拟地址空间時,完全不进行限制这种情况下,避免了fork可能产生的失败但由于malloc是先分配虚拟地址空间,而后通过异常陷入内核分配真正的物理内存在内存不足的情况下,这相当于完全屏蔽了应用进程对系统内存状态的感知即malloc总是能成功,一旦内存不足会引起系统OOM杀进程,应用程序对于这种后果是无法预测的

    取值为2则是根据系统内存状态确定了虚拟地址空间的上限,由于很多情况下进程的虚拟地址空间占用遠大小其实际占用的物理内存,这样一旦内存使用量上去以后对于一些动态产生的进程(需要复制父进程地址空间)则很容易创建失败,如果业务过程没有过多的这种动态申请内存或者创建子进程则影响不大,否则会产生比较大的影响

    linux系统下查看CPU、内存负载情况


我要回帖

更多关于 三张信用卡如何循环使用 的文章

 

随机推荐