美文网首页
iOS知识整理-内存

iOS知识整理-内存

作者: 皮皮蟹pipixie | 来源:发表于2019-10-15 14:17 被阅读0次

    内存布局

    1782258-c982ebeacd0a42dc.png
    • 栈(stack):方法调用,局部变量等,是连续的,高地址往低地址扩展
    • 堆(heap):通过alloc等分配的对象,是离散的,低地址往高地址扩展,需要我们手动控制
    • 未初始化数据(bss):未初始化的全局变量等
    • 已初始化数据(data):已初始化的全局变量等
    • 代码段(text):程序代码

    MRC与ARC

    MRC:
    手动引用计数,手动添加retain, release

    //MRC下的setter方法
    - (void)setString:(NSString *)string{
        if (_string != string) {
            [string retain];
            [_string release];
            _string = string;
        }
    }
    

    ARC:
    自动引用计数,系统自动添加内存操作。但有些地方需要注意。
    1.循环引用
    block引起的循环引用,会强引用回调中使用的对象
    NSTimer引起的循环引用,会强引用target
    performSelector:afterDelay的问题,会强引用target,当方法一直没调用时,target会不能释放
    2.NSNotification
    通知的addObserver会建立一个弱引用到接收者,不会发生内存泄露的问题。但是我们需要在dealloc里面调用removeObserver,避免通知的时候,对象已经被销毁,这时候会发生crash.
    参考:ARC下需要注意的内存管理
    ~

    Copy协议

    在iOS中并不是所有对象都支持Copy和MutableCopy,遵循NSCopying协议的类可以发送Copy协议,遵循NSMutableCopying协议的类可以发送MutableCopy消息。如果一个对象没有遵循这两个协议而发送Copy或者MutableCopy消息那么会发生异常。如果要遵循NSCopying协议,那么必须实现copyWithZone方法。
    如果要遵循NSMutableCopying协议那么必须实现mutableCopyWithZone方法。
    对于自定义对象来说调用Copy和MutableCopy方法都会重新分配一块内存。

    //  Man.h
    #import <Foundation/Foundation.h>
    
    @interface Man : NSObject<NSCopying,NSMutableCopying>
    @property (nonatomic,strong)NSString *name;
    @property (nonatomic,assign)NSInteger year;
    @end
    
    //  Man.m
    #import "Man.h"
    
    @implementation Man
    #pragma mark description方法内部不能打印self,不然会造成死循环
    - (NSString *)description {
        return [NSString stringWithFormat:@"[name = %@,year = %ld]", _name,_year];
    }
    //自定义深拷贝,实现copyWithZone方法
    -(id)copyWithZone:(NSZone *)zone{
        Man *newMan = [[[self class] allocWithZone:zone] init];
        newMan.name = self.name;
        newMan.year = self.year;
        return newMan;
    }
    
    -(id)mutableCopyWithZone:(NSZone *)zone{
        Man *newMan = [[[self class] allocWithZone:zone] init];
        newMan.name = self.name;
        newMan.year = self.year;
        return newMan;
    }
    @end
    
    //调用
        Man *man = [[Man alloc]init];
        man.name = @"张三";
        man.year = 1;
        Man *newMan = [man copy];
        Man *newMutMan = [man mutableCopy];
    

    ~

    weak

    weak是Runtime维护了一个hash(哈希)表,用于存储指向某个对象的所有weak指针。weak表其实是一个hash(哈希)表,Key是所指对象的地址,Value是weak指针的地址(这个地址的值是所指对象指针的地址)数组。
    __unsafe_unretained 与 weak 比较,__weak需要检查对象是否已经消亡,需要一些信息去跟踪对象的使用情况。也正因此,__unsafe_unretained 比 __weak快,当明确知道对象的生命期时,选择__unsafe_unretained 会有一些性能提升,而当情况不确定的时候,应该优先选用 __weak 。
    参考:iOS内存管理(4)-引用计数的存储、weak原理
    ~

    autoreleasepool

    自动释放池,原理就不深究了,主要功能是让autorelease对象在释放池结束时才释放。
    在ARC环境下使用的主要场景,在for循环alloc图片数据等内存消耗较大的场景。因为此时只有在for循环结束后(准确说是当前runloop结束后)才会释放临时对象,当入释放池后,能在每个循环结束时释放内存。
    参考:iOS内存管理(5)-autorelease原理和autorelease和runloop的结合使用

    相关文章

      网友评论

          本文标题:iOS知识整理-内存

          本文链接:https://www.haomeiwen.com/subject/vthxmctx.html