- 简要说一下
autoreleasePool
的数据结构
简单说是
双向链表
,每张链表头尾相接,有parent、child
指针,每创建一个池子,会在首部创建一个哨兵
对象作为标记,最外层池子的顶端会有一个next
指针。当链表容量满了,就会在链表的顶端,并指向下一张表
- 说一下
autoreleasePool
的实现原理
autoreleasePool
是一个延时release
的机制,在自动释放池被销毁或耗尽时,会向池中的所有对象发送release
消息,释放所有autorelease
对象
autoreleasePool
并没有单独的结构,而是由若干个autoreleasePoolPage
作为结点以双向链表
的形式组合而成
- 每一个指针代表一个加入到释放池的
对象
或者是哨兵
对象,哨兵对象是在@autoreleasepool{}
构建的时候插入的- 当自动释放池
pop
的时候,所有哨兵对象之后的对象都会release
- 链表会在一个
Page
空间占满时进行增加,一个autoreleasePoolPage
的空间被占满时,会新建一个autoreleasePoolPage
对象连接链表,后来的autorelease
对象在新的page
加入
- 解释一下三次握手和四次挥手
- 三次握手
- 由客户端向服务端发送
SYN
同步报文- 当服务端收到
SYN
同步报文之后,会返回给客户端SYN
同步报文和ACK
确认报文- 客户端会向服务端发送
ACK
确认报文,此时客户端和服务端的连接正式建立
- 四次挥手
- 先由客户端向服务端发送
FIN
结束报文- 服务端会返回给客户端
ACK
确认报文。此时,由客户端发起的断开连接已经完成- 服务端会发送给客户端
FIN
结束报文和ACK
确认报文- 客户端会返回
ACK
确认报文到服务端,至此,由服务端方向的断开连接已经完成
拓展:
SYN
攻击
在三次握手过程中,Server
发送SYN-ACK
之后,收到Client
的ACK
之前的TCP
连接称为半连接half-open connect
,此时Server
处于SYN_RCVD
状态,当收到ACK
后,Server
转入ESTABLISHED
状态。SYN
攻击就是Client
在短时间内伪造大量不存在的IP
地址,并向Server
不断地发送SYN
包,Server
回复确认包,并等待Client
的确认,由于源地址是不存在的,因此,Server
需要不断重发直至超时,这些伪造的SYN
包占用未连接队列,导致正常的SYN
请求因为队列满而被丢弃,从而引起网络堵塞甚至系统瘫痪。SYN
攻击时一种典型的DDOS
攻击
一般有两种方式
1、客户端恶意不发送ACK
2、在发送给服务器的SYN
报文段中提供虚假的IP
地址,造成服务器永远收不到ACK
- 一个
NSObject
对象占用多少内存
一个指针变量所占用的大小,
64bit
占8
个字节,32bit
占4
个字节
- 对象的
isa
指针指向哪里
instance
对象的isa
指针指向class
对象,class
对象的isa
指针指向meta-class
对象,meta-class
对象的isa
指针指向基类的meta-class
对象,基类自己的isa
指针也指向自己
-
OC
的类信息存放在哪里
成员变量的具体值存放在
instance
对象,对象方法、协议、属性、成员变量信息存放在class
对象,类方法信息存放在meta-class
对象
- 为什么使用
runtime
技术中的关联对象可以为类别添加属性
关联对象都由
AssociationsManager
管理,AssociationsManager
里面是由一个静态AssociationsHashMap
来存储所有的关联对象的。这相当于把所有对象的关联对象都存在一个全局map
里面。而map
的key
是这个对象的指针地址,而这个map
的value
又是另外一个AssociationsHashMap
,里面保存了关联对象的kv
对
- 用过哪些锁?哪些锁的性能比较高?谈下
Objective-C
都有哪些锁机制,你一般用哪个
常用的锁有
NSLock、@synchronized代码块、信号量 dispatch_semaphore_t
os_unfair_lock
(推荐)
dispatch_semaphore
(推荐)
pthread_mutex
(推荐)
dispatch_queue(DISPATCH_QUEUE_SERIAL)
(推荐)
NSLock
()
NSCondition
()
@synchronized
(最不推荐)
信号量性能最高
@synchronized
代码块最方便
- 为什么一定要在主线程里面更新
UI
UIKit
不是线程安全的,容易产生UI
更新上的混乱
- 类和结构体的区别
类是引用类型,结构体是值类型。结构体变量分配在栈,
OC
对象分配在堆。结构体只能封装属性,类不仅可以封装属性也可以封装方法
- 引用和指针的区别
指针的本质也就是变量,它不仅有自己的地址,也有它所存放的值,只不过这个值是地址而已
引用也就是指针常量,它是一个对象的别名,既然初始化了所指向的地址,那么它一定不为空,而且地址不可变
引用必须被初始化,指针不必
引用初始化以后不能被改变,指针可以改变所指的对象
不存在指向空值的引用,但存在指向空值的指针
-
id
类型、nil
、Nil
、NULL
和NSNULL
的区别
id
类型是一个独特的数据类型,可以转换为任何数据类型,id类型的变量可以存放任何数据类型的对象,id
声明的对象具有运行时特性,可以指向任意类型的对象
nil
是一个实例对象值,如果我们要把一个对象设置为空的时候就用nil
Nil
是一个类对象的值,如果我们要把一个class
的对象设置为空的时候就用Nil
NULL
指向基本数据类型的空指针C语言的变量的指针为空
NSNull
是一个对象,它用在不能使用nil
的场合
-
weak
的底层实现的原理是什么
weak
表其实是一个hash
哈希表,Key
是所指对象的地址,Value
是weak
指针的地址数组
runtime
维护了一个weak
表,用于存储指向某个对象的所有weak
指针,weak
表其实是一个hash
表,Key
是所指对象的地址,value
是weak
指针的地址数组
为什么value
是数组?因为一个对象可能被多个弱引用指针指向
-
weak
原理实现步骤
weak
的实现原理可概括三步
- 初始化时:
runtime
会调用objc_initWeak
函数,初始化一个新的weak
指针指向对象的地址- 添加引用时:
objc_initWeak
函数会调用objc_storeWeak()
函数,objc_storeWeak()
的作用是更新指针指向,创建对应的弱引用表- 释放时,调用
clearDeallocating
函数,clearDeallocating
函数首先根据对象地址获取所有weak
指针地址的数组,然后遍历这个数组把其中的数据设为nil
,最后把这个entry
从weak
表中删除,最后清理对象的记录
- 编译过程做了哪些事情
Objective、Swift
都是编译语言。编译语言在执行的时候,必须先通过编译器生成机器码,机器码可以直接在CPU
上执行,所以执行效率较高
Objective、Swift
二者的编译都是依赖于Clang + LLVM
不管是OC
还是Swift
,都是采用Clang
作为编译器前端,LLVM(Low level vritual machine)
作为编译器后端
- 编译器前端:编译器前端的任务是进行语法、语义分析,生成中间代码。在这个过程中会进行类型检查,如果发现错误或者警告会标注出来在哪一行
- 编译器后端:编译器后端会进行机器无关的代码优化,生成机器语言,并且进行机器相关的代码优化。
LLVM
优化器会进行BitCode
的生成,链接器优化等等,LLVM
机器码生成器会针对不同的架构,比如arm64
等生成不同的机器码
-
Linux
命令之-Strings
strings
命令是在对象文件或者二进制文件中查找可打印的字符串,常用来在二进制文件中查找字符串,与grep
配合使用,例如一个用法就是在编译的so
中定义字符串常量作为动态库的版本号,然后就可以使用strings+grep
组合命令查看当前编译的so
的版本号了。输入strings -h
查看strings
命令的用法,下面为具体用法实例
strings /lib/tls/libc.so.6 | grep GLIBC
strings /Users/y**ar/Desktop/Demo2/Libraries/libiPhone-lib.a | grep "UIWebView"
cat /Users/y**ar/Desktop/Demo2/Libraries/libiPhone-lib.a
-
OC
格式化打印
%d
整数
%02d
表示不足2
位补0
%u
无符号整型
%f
浮点(双字节)
%.2f
精度浮点数,只保留两位小数
%x,%X
十六进制整数
%o
八进制整数
%p
指针
%s
C
字符串
%c
字符
网友评论