内存管理

2023-07-11  本文已影响0人  万万万万万万一

1.引用计数

OC类中实现了引用计数器,对象知道自己当前被应用的次数。对象初始化时计数器+1,每次操作对象都会引起相应的计数器变化。returen+1, release-1;当引用计数为0时,给oc对象发送delloc消息。

黄金法则

凡通过alloc, init, copy, mutableCopy, return进行创建的对象,都要使用release或autorelease进行释放。

1.自己生成的对象,自己持有

2.不是自己生成的对象,自己也能持有

3.不需要持有的对象要释放

4.非自己持有的对象无需释放

引用计数存放

从64bit开始,对象的引用计数存放在优化过的isa指针中,也可能存放在SideTable中。当优化过的isa指针中,引用计数过大存不下时,就会将引用计数存放到SideTable中。

SideTable包含自旋锁,引用计数表,弱引用表,有Runtime维护

SideTables其实是一个哈希表,key为对象的指针,value为对象内容 存放在SideTable。

为什么是SideTables?

因为查找或修改引用计数时是要枷锁的,使用SideTables方便多个对象同时做操作。


2.MRC

iOS5之前,需要开发者手动管理内存。

需要引用对象时,发送retain消息,对象引用计数器+1;

不需要引用对象时,发送release消息,对象引用计数器-1;

当引用计数为0时,自动调用对象的dealloc方法销毁对象,释放内存;

引用计数为0时的对象,不能再使用release和其它方法。


3.ARC

ARC也是基于引用计数,只是编译器在编译时自动在已有代码中插入合适的内存管理代码(包括retain,release,copy,autorelease,autoreleasepool)以及在运行时做了一些优化。简单说,就是代码中自动加入了retain,release,原先MRC中需要手动添加时用来管理引用计数器的代码都有编译器来帮我们完成。


4.strong,weak,assign

strong:强引用,指向一个对象时,对象引用计数+1;当对象没有一个强引用指向它时,它才会释放。如果在声明时不加修饰符,默认strong。

weak:弱引用,不会引起对象的引用计数变化;当对象被释放时,所指向它的弱引用指针会自动被设置为nil,防止野指针。

weak原理:对象的SideTable中有一个weak表,以对象的内存地址为key,value则是所有指向该该对象的弱引用指针数组。当对象销毁时,通过对象内存地址找到所有指向该对象的地址数组,遍历这个数组 把其中的数据设置成nil ,然后把这个entry从weak表中删除,最后清理对象记录。

weak底层实现:

1.初始化时,runtime会调用objc_initWeak函数 初始化一个新的weak指针指向对象地址

2.添加引用时:objc_initWeak函数 会调用objc_storeWeak函数 在objc_storeWeak函数作用下更新指针指向,创建对应的弱引用表。

3.释放时:调用clearDeallocating函数先根据对象地址获取所有的weak指针的地址数组,遍历这个数组 把其中的数据设置成nil ,然后把这个entry从weak表中删除,最后清理对象记录。


5.深copy与浅copy

1.非容器对象:

对不可变对象 copy是指针复制(浅拷贝),mutablecopy是深拷贝

可变对象 copy和mutablecopy 都是深拷贝

2.容器对象:

对不可变对象 copy是指针复制(浅拷贝),mutablecopy是深拷贝

可变对象 copy和mutablecopy都是深拷贝只是返回的对象类型不一样copy是不可变对象,mutablecopy是可变对象


6.atomic和nonatomica

对atomic修饰的属性的setter、getter方法添加了原子锁,保证set、get操作的完整性。

也就是下一次的set、get操作必须等到上一次的set、get操作完成之后才能执行。

因为atomic添加了原子锁,会增加开销,运行速度更慢,在不需要保证set、get操作的完整的情况下,所以一般都使用nonatomic。

atomic不能完全保证线程安全

只能保证set、get操作的完整性,当开启多个线程执行多个set、get操作时,无法保证执行的顺序。

另外如数组除了set、get操作外还有remove的操作。


7.内存泄漏和溢出

内存泄漏:是指申请的内存空间用完之后未释放,在ARC下根本原因是循环引用(在ViewController中没有正确的使用NStimer、delegate、block)引起的。

内存溢出:通俗的讲就是内存不够用了,程序申请内存空间时,没有足够的内存空间可供使用。


8.循环引用

两个对象之间相互强引用,引用计数都依赖于对方,导致对象无法释放。

最容易产生循环引用的两种情况就是delegate和block,所以才引入了弱引用。

持有对象,但不增加引用计数,这样就避免了循环引用的产生。


上一篇下一篇

猜你喜欢

热点阅读