内存管理

2020-12-23  本文已影响0人  羽裳有涯

1、何检测内存泄漏

泄露的内存主要有以下两种:

2、循环引用

实质:多个对象相互之间有强引用,不能释放让系统回收。

如何解决循环引用?

MRC 下,__block不会增加其引用计数,避免了循环引用
ARC 下,__block 修饰对象会被强引用,无法避免循环引用,需要手动解除。

NSTimer 循环引用属于相互循环使用
创建 NSTimer 作为其属性,由于定时器创建后也会强引用该控制器对象,那么该对象和定时 器就相互循环引用了。
将定时器invalidate 并置为nil 即可

3、悬垂指针?野指针?

悬垂指针:指针指向的内存已经被释放了,但是指针还存在,这就是一个 悬垂指针 或者说 迷途指针

野指针: 没有进行初始化的指针,其实都是 野指针

retain,copy,assign,weak,_Unsafe_Unretain

Strong 修饰符表示指向持有该对象,其修饰对象的引用计数会加 1。该对象只要引用计数不为 0 就不会 被销毁。当然可以通过将变量强制赋值 nil 来进行销毁。

weak 修饰符指向但是并不持有对象,引用计数也不会加 1。在 Runtime 中对该属性进行了相关操作, 无需处理,可以自动销毁。weak 用来修饰对象,多用于避免循环引用的地方。weak 不可以修饰基本数据 类型。

assign主要用于修饰基本数据类型, 例如 NSInteger,CGFloat,存储在栈中,内存不用程序员管理。assign 是可以修饰对象的,但是会出现问 题。

copy 关键字和 strong 类似,copy 多用于修饰有可变类型的不可变对象 NSString,NSArray,NSDictionary 上。

__unsafe_unretain 类似于weak ,但是当对象被释放后,指针已然保存着之前的地址,被释放后的地址 变为 僵尸对象,访问被释放的地址就会出问题,所以说他是不安全的。

__autoreleasing 将对象赋值给附有 __autoreleasing 修饰的变量等同于 ARC 无效时调用对象的 autorelease 方法,实质 就是扔进了自动释放池。

4、深拷贝 和 浅拷贝 集合类深拷贝如何实现

深拷贝: 该对象是否复制一份,内容拷贝
浅拷贝: 指针拷贝,

对于集合对象的内容复制仅仅是对对象本身,但是对象的里面的元素还是指针复制。要想复制整个 集合对象,就要用集合深复制的方法,有两种:

(1)使用 initWithArray:copyItems:方法,将第二个参数设置为 YES 即可

NSDictionary * dct  = [[NSDictionary alloc] initWithDictionary:dicto copyItems:YES]

(2)将集合对象进行归档(archive)然后解归档(unarchive):

 NSArray *trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:oldArr]]

5、Dealloc 的实现机制

一、Dealloc调用流程

- (void)dealloc {
    _objc_rootDealloc(self);
}
void _objc_rootDealloc(id obj)
{
    assert(obj);

    obj->rootDealloc();
}
inline void objc_object::rootDealloc(){
    if (isTaggedPointer()) return;  // fixme necessary?

    if (fastpath(isa.nonpointer  &&  
                 !isa.weakly_referenced  &&  
                 !isa.has_assoc  &&  
                 !isa.has_cxx_dtor  &&  
                 !isa.has_sidetable_rc))
    {
        assert(!sidetable_present());
        free(this);
    } 
    else {
        object_dispose((id)this);
    }
}
id object_dispose(id obj)
{
    if (!obj) return nil;

    objc_destructInstance(obj);    
    free(obj);

    return nil;
}

2.object_dispose() 调用流程。

id 
object_dispose(id obj)
{
    if (!obj) return nil;

    objc_destructInstance(obj);    
    free(obj);

    return nil;
}

3.objc_destructInstance() 调用流程

void *objc_destructInstance(id obj) 
{
    if (obj) {
        // Read all of the flags at once for performance.
        bool cxx = obj->hasCxxDtor();
        bool assoc = obj->hasAssociatedObjects();

        // This order is important.
        if (cxx) object_cxxDestruct(obj);
        if (assoc) _object_remove_assocations(obj);
        obj->clearDeallocating();
    }

    return obj;
}

4.clearDeallocating() 调用流程。

inline void 
objc_object::clearDeallocating()
{
    if (slowpath(!isa.nonpointer)) {
        // Slow path for raw pointer isa.
        sidetable_clearDeallocating();
    }
    else if (slowpath(isa.weakly_referenced  ||  isa.has_sidetable_rc)) {
        // Slow path for non-pointer isa with weak refs and/or side table data.
        clearDeallocating_slow();
    }

    assert(!sidetable_present());
}

7 、内存中的 5 大区

8、内存管理方案

  • 散列表第一位的 0 或 1 代表是纯地址型 isa 指针,还是 NONPOINTER_ISA 指针。
  • 第二位,代表是否有关联对象
  • 第三位代表是否有 C++ 代码。
  • 接下来 33 位代表指向的内存地址
  • 接下来有 弱引用 的标记
  • 接下来有是否 delloc 的标记....等等
  • SideTables表在 非嵌入式的 64 位系统中,有 64 张 SideTable 表
  • 每一张 SideTable 主要是由三部分组成。自旋锁、引用计数表、弱引用表
  • 全局的 引用计数 之所以不存在同一张表中,是为了避免资源竞争,解决效率的问题。
  • 引用计数表 中引入了 分离锁的概念,将一张表分拆成多个部分,对他们分别加锁,可以实现并发操 作,提升执行效率

自旋锁:

引用计数表和弱引用表实际是一个哈希表,来提高查找效率。

9、内存布局

10、@dynamic

@dynamic 意味着编译器不会帮助我们自动合成 settergetter 方法。我们需要手动实现、这里就涉及 到 Runtime 的动态添加方法的知识点。

11、@autoreleasePool 的数据结构

objc_autoreleasePoolPush: 把当前 next 位置置为 nil,即哨兵对象,然后 next 指针指向下一个可入栈位置, AutoreleasePool 的多层嵌套,即每次 objc_autoreleasePoolPush,实际上是不断地向栈中插入哨兵 对象。
objc_autoreleasePoolPop: 根据传入的哨兵对象找到对应位置。 给上次 push 操作之后添加的对象依次发送release 消息。 回退next指针到正确的位置。

12、弱引用管理

__weak 属性修饰的变量,如何实现在变量没有强引用后自动置为 nil ?

用的弱引用 - weak表。也是一张 哈希表。
weak修饰的指针变量所指向的地址是 key ,所有指向这块内存地址的指针会被添加在一个数组里, 这个数组是 Value。当内存地址销毁,数组里的所有对象被置为 nil。
weak修饰的指针变量,在指向的内存地址销毁后,会在 Runtime 的机制下,自动置为nil

上一篇 下一篇

猜你喜欢

热点阅读