内存管理 以及 OC中的属性关键字

1.定时器
CADisplayLink、NSTimer会对target强引用,target又对它们强引用,就会引发循环引用
解决方案
block
代理对象NSProxy
NSTimer依赖于RunLoop,当RunLoop的任务过于繁重,会导致NSTimer不准时
GCD定时器更准时
2.内存布局:从低到高依次是保留、代码段.text(编译之后的代码)、数据段(字符串常量、已.data/未.bss初始化全局/静态变量等数据)、堆heap(通过a/m/calloc的等动态分配空间,分配的内存空间地址从低到高,向上增长,越来越大 创建的对象或block经过copy之后被转移到堆上)、栈stack (局部变量等方法函数调用开销,分配的内存空间地址从高到低,向下扩展,越来越小)、内核区
3.内存管理方案:Tagged Pointer、NonPointer_ISA、散列表
Tagged Pointer从64bit开始,优化NSNumber、NSDate、NSString等小对象的存储
在此使用之前,NSNumber指针存储的是堆中该对象的地址值;使用之后,NSNumber指针直接存储数据变成了Tag+Data,只有指针不够存储数据时,才用动态分配内存的方式。 objc_msgSend能识别Tagged Pointer如NSNumber的intValue方法,直接从指针读取数据,节省调用开销。
如何判断一个指针是Tagged Pointer?iOS最高有效位1 Mac最低DA有效位1
查看自动释放池的情况 extern void _objc_autoreleasePoolPrint(void)
带mutable的属性的copy是深拷贝,任意属性的mutableCopy都是深拷贝
引用计数的存储:在64bit中,引用计数可直接存储在优化过的isa指针中,也可存储在SideTable类中
struct SideTable{
spinlock_t slock; //自旋锁 当前锁已被其他线程获取,当前线程会不断探测锁是否被释放,若释放掉自己会第一时间去获取这个锁。
RefcountMap refcnts; //存放对象引用计数的散列表
weak_table_t weak_table; //弱引用表
}
自旋锁 忙等的锁当前锁已被其他线程获取,当前线程会不断探测锁是否被释放,若释放掉自己会第一时间去获取这个锁。信号量,当它获取不到这个锁,会把自己当前线程进行阻塞休眠,然后等其他线程释放锁的时候,唤醒线程。
适用于轻量访问。
为什么是好几张表组成SideTables?
假如只有一个SideTable,相当于所有对象的引用计数和弱引用都放到一张大表里,此时若操作某一对象的引用计数值进行修改如+1或-1,由于所有对象可能在不同线程分配和创建甚至调用release retain方法,这时对表进行操作需要进行加锁操作以保证数据访问安全,就存在效率问题!比如说用户内存4GB,分配出成千上百万对象,如果每个对象对它进行内存引用计数的改变时都操作这张表,若有对象正在操作这张表,下一对象就需要等它操作完把锁释放之后才能进行操作,就会有效率问题,为解决这个问题引入了分离锁!内存对象对应的引用计数表分拆成多个部分如8个,需要对它们分别加锁,A和B对象在不同表里面,当它们同时引用计数操作就可以并非发操作。而若在同一张表里,就需要顺序操作。
怎样实现快速分流?
SideTables本质是一张Hash表,
对象指针作为Key 经过Hash函数的运算,计算出一个Value即对象对应的SideTable是哪张
Hash查找 比如给出对象内存地址,目标值是数组下标索引;通过对象内存地址与SideTables数组的个数取余,这个过程不涉及遍历,所以查找效率比较高。该哈希函数为均匀散列函数。

4.数据结构
5.MRC和ARC
copy
引用计数原理
weak 将弱引用存储到哈希表里面,当对象销毁,取出当前对象的弱引用表,把弱引用表里面存储的弱引用都清除掉
ARC利用LLVM编译器自动帮我们生成release,retain,autorelease 在运行时处理像weak的存在是需要runtime的支持
alloc经过一系列的调用,最终调用C函数的calloc,此时并没有设置引用计数为1
retain 通过当前对象的指针到SideTables(由多个SideTable组成的哈希表)中去获取它所属的sideTable。
当获取到这个对象引用计数相关的SideTable,再到该SideTable里面去获取引用计数map,通过当前对象的指针在SideTable引用计数表中获取当前对象的引用计数值,refcnts就是SideTable中的成员变量也是SideTable中的引用计数表,这个查找的过程也是哈希查找。所以retain操作经历了2次哈希查找。
存储引用计数的变量size_t是无符号long型值,对引用计数值refcntStorage进行+1=SIDE_TABLE_RC_ONE(偏移量)操作
release 前2步与retain相同 查找到引用计数表以后,进行-操作
retainCount 第一步找到SideTable;然后声明局部变量,指定其值为1;然后通过当前对象到引用计数表中去查找,把查找的结果作一个向右偏移的操作,再结合这个局部变量的1进行+操作,
dealloc 当对象要释放时调用dealloc,接下来是调用轨迹,
objc_rootDealloc
rootDealloc
object_dispose
objc_destructInstance
free
6.AutoreleasePoolPage原理
autorelease 调用该对象最终通过AutoreleasePoolPage对象来管理,自动释放池的主要底层数据结构_At~、~Page
每个AutoreleasePoolPage 占4096字节,存放内部成员变量,剩余的存放autorelease对象的地址
所有AutoreleasePoolPage通过双向链表连接在一起,AutoreleasePoolPage *child指向另一AutoreleasePoolPage *child,下一个 parent指向上一个pthread_t thread;
调用push会将POOL_BOUNDARY入栈 ,并返回其存放的内存地址
pop传入POOL_BOUNDARY内存地址,会从最后一个入栈对象开始发送release对象,直到遇到该POOL_BOUNDARY
id *next指向下一个能存放autorelease对象地址的区域
RunLoop和Autorelease
iOS在主线程的RunLoop中注册2个Observer,第一个Observer监听了kCFRunLoopEntry事件,会调用objc_autoreleasePoolPush( ),第二个Observer监听了kCFRunLoopBeforeWaiting事件,会调用objc_autoreleasePoolPush( )/Pop,I 监听了kCFRunLoopBeforeExit,会调用 Pop

OC中的属性关键字

一、@property属性

声明一个property时编译器自动生成setter和getter方法

简单的命名约定,getter名字与属性名相同(如date),setter名字在属性名前加set并遵守驼峰命名规则(如setDate).布尔类型可定义以is开头的getter方法(如@property(readonly,getter=isBule)BOOL blue;)

1.1@synthesize 和 @dynamic 分别有什么作用?

@property 有两个对应的词,一个是 @synthesize,一个是 @dynamic。如果 @synthesize 和 @dynamic 都没写,那么默认的就是 @syntheszie var = _var;

@synthesize 的语义是如果你没有手动实现 setter 方法和 getter 方法,那么编译器会自动为你加上这两个方法。

@dynamic 告诉编译器:属性的 setter 与 getter 方法由用户自己实现,不自动生成。(当然对于 readonly 的属性只需提供 getter 即可)。假如一个属性被声明为 @dynamic var,然后你没有提供 @setter 方法和 @getter 方法,编译的时候没问题,但是当程序运行到 instance.var = someVar,由于缺 setter 方法会导致程序崩溃;或者当运行到 someVar = var 时,由于缺 getter 方法同样会导致崩溃。编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定。

二、 readonly,readwrite

readonly只有一个访问方法即getter方法

readwrite有两个访问方法

三、nonatomic,atomic

atomic并非线程安全,只保证赋值和获取线程安全(setter和getter方法内部加了同步线程的锁),并不代表操作和访问(如给数组添加移除操作对象,不保证线程安全)

atomic相较于nonatomic更号资源,速度要慢,所以在iphone等小型设备,若没有多线程间的通讯建议用nonatomic

四、 assign,retain, weak,strong,copy

assign、retain 是 MRC(默认assign) 时的关键字,到 ARC 时(默认是strong只能修饰对象和id,基本数据类型是assign)换成了 strong 和 weak 。

weak 是用来修饰代理(delegate)和UI控件。

strong 是用来修饰除了代理(delegate)、UI控件、字符串(NSString)以外的对象类型。

copy 是用来修饰字符串(NSString)。

assign 是用来修饰基本数据类型(非对象类型),如:int、float、bool、menu等。

4.1为什么用assign能修饰基本数据类型?

基本数据类型是分配在栈上,栈内存由系统自己自动处理回收,不会造成野指针。

4.2copy 深拷贝,浅拷贝

无论对象是否可变,mutablecopy深拷贝 得到可变对象

copy后都不可变,可变对象的copy深拷贝 不可变对象的copy浅拷贝

4.3NSString使用copy修饰不用strong修饰?

strong浅拷贝,指针引用

copy修饰复习,即时属性拷贝来自可变字符串,也会被深拷贝成不可变字符串。源头字符串修改后不会影响属性字符串,增强了代码的健壮性。

https://www.jianshu.com/p/eda4957735ee

4.4weak实现原理?

4.5

五、unsafe_unretained

unsafe_unretained可修饰基本数据类型和对象,iOS之后用weak代替。其修饰的变量不属于编译器的内存管理对象。

unsafe_unretained和_weak一样,对象的弱引用关系。唯一区别:unsafe_unretained修饰的对象被释放后,指针不会置空,而是变成野指针,导致内存泄漏,程序crash,p抛出Bad_Access异常

六、__ weak、__ unsafe_unretained 、__ block、__ strong、__ copy 、__autorelease 等

类似这样的关键字,其实和没有‘__’还是一样,只是在 .m 中声明就是这个样子,另外提到 .m 文件中,新生产的对象,其实默认都有 __strong 。

6.1指针用什么修饰引用计数不增加?

__ weak、__ unsafe_unretained

七、nonnull、nullable、null_resettable、__ null _unspecified、 _ kindof

nonnull不能为空

nullable可以为空

null_resetable 必须重写get方法,set可为空

__ null _unspecified不确定是否为空

_kindof放在类型前面,表示当前类,也可以表示当前类的子类

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值