美文网首页
内存管理

内存管理

作者: bytebytebyte | 来源:发表于2021-04-13 10:02 被阅读0次
    1.理解NSProxy
    ViewController *vc = [[ViewController alloc] init];
    MJProxy:NSProxy
    MJProxy *proxy1 = [MJProxy proxyWithTarget:vc];  
    MJProxy1:NSObject
    MJProxy1 *proxy2 = [MJProxy1 proxyWithTarget:vc];
    NSLog(@"%d %d",[proxy1 isKindOfClass:[ViewController class]], [proxy2 isKindOfClass:[ViewController class]]); 1 0
    解释:
    //[proxy1 isKindOfClass:[ViewController class]]不继承NSObject不走消息发送,直接走了消息转发
    调用对象时vc
    //[proxy2 isKindOfClass:[ViewController class]])调用对象是NSObject
    
    @implementation MJProxy
    + (instancetype)proxyWithTarget:(id)target{
        // NSProxy对象不需要调用init,因为它本来就没有init方法
        MJProxy *proxy = [MJProxy alloc];
        proxy.target = target;
        return proxy;
    }
    - (NSMethodSignature *)methodSignatureForSelector:(SEL)sel{
        return [self.target methodSignatureForSelector:sel];
    }
    - (void)forwardInvocation:(NSInvocation *)invocation{
        [invocation invokeWithTarget:self.target];
    }
    @end
    @implementation MJProxy1
    + (instancetype)proxyWithTarget:(id)target{
        MJProxy1 *proxy = [[MJProxy1 alloc] init];
        proxy.target = target;
        return proxy;
    }
    - (id)forwardingTargetForSelector:(SEL)aSelector{
        return self.target;
    }
    @end
    
    2.GCD不会产生循环引用,为什么?
    diapatch_asyn^{ self }
    因为只是产生了单方面的循环引用,GCD强引用了self,self没有强引用GCD。
    Masonry的make同理不会。
    
    3.如何解决NSTimer循环应用?
    (1)使用GCDTimer,其跟系统内核有关,不会产生循环引用。
    考虑 信号量,字典[@"1",timer]
    (2)使用中间类 弱引用当前对象self和NSTimer
    (3)使用NSProxy防止循环引用
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:[MJProxy proxyWithTarget:self] selector:@selector(timerTest) userInfo:nil repeats:YES];
    
    4.CADisplayLink、NSTimer应注意什么?
    会导致循环引用,都依赖NSRunloop,当CPU需要处理大量事件时会会不精准。
    
    5.内存布局是什么样子的?栈堆正好高低 就记住了
            保留
    低    代码段  编译后的代码
            数据段   字符串常量
                          已初始化数据:已初始化全局变量、静态变量
                          未初始化数据:未初始化全局变量、静态变量
             堆↓  alloc、malloc、calloc 分配内存空间越来越小  特点:程序员自己管理
    高      栈↑  局部变量  分配内存空间越来越大 特点:系统管理
              内核区
    
    6.TaggedPointer 技术:直接从指针提取数据,目的节省内存空间,使用效率的优化。
    使用TaggedPointer 之前
    number=0x10001  →  地址:0x10001 存储值:10
    使用TaggedPointer 之后
    number=0xb000a1  b和1是tag pointer中的a是值
    
    当TaggedPointer技术存不下太大的值时又恢复成了number对象存值。
    objc_msgSend能够识别Tagged Pointer,如NSNumber的IntValue方法,从中直接提取数据
    NSNumber、NSDate、NSString用
    
    7.ARC的本质?是转化成MRC
    @property (copy) NSString *name;
    - (void)setName:(NSString *)name {
                if (_name != name) {
                              [_name release];先干掉旧的 再赋值新的
                              _name = [name copy];//_name = [name retain]; strong修饰变成retain其他不变
                 }
    }
    
    这两段代码会发生什么事?如何处理?有什么区别?
    @property (strong, nonatomic) NSString *name;
    //    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    //    for (int i = 0; i < 1000; i++) {
    //        dispatch_async(queue, ^{
    //            // 加锁
    //5            self.name = [NSString stringWithFormat:@"abcdefghijk"];
    //            // 解锁
    //        });
    //    }
    发生坏内存访问,因为第5句代码self.name时OC对象,在多线程下 [_name release]执行了2次即_name被释放了2次,第2次已经释放了又去访问。应加锁。
        
    //    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    //    for (int i = 0; i < 1000; i++) {
    //        dispatch_async(queue, ^{
    // 10           self.name = [NSString stringWithFormat:@"abc"];
    //        });
    //    }
    不会发生坏内存访问。因为第10句self.name是taggedPointer不是OC对象,是指针赋值,没有调用setter方法,也不存在release。
    
    8.理解MRC
    4中情况 归根结底是第一种情况。
    (1)一个alloc对应一个release或者autorelease,release在不用的时候release,怕忘记直接alloc后autorelease即可。
    (2)一个@property (retain,nonatomic) NSMutableArray *data对应dealloc里的一个self.data = nil。
    (3)一个self.data = [NSMutableArray array]和new对应dealloc里的一个self.data = nil,因为内部已经autorelease过了。
    (4)非属性遵循(1)即可
    
    + (instencetype)array {
            return [[[self alloc]init] autorelease];
    }
    @property (retain,nonatomic) NSMutableArray *data;
    
    viewdidload{
            self.data = [NSMutableArray array];
             Person *person = [[[Person alloc]init]autorelease];
    }
    
    dealloc {
              self.data = nil;
    }
    
    9.理解copy .一个copy相当于调用一个retain需要对应一个release,把copy后的对象当成一个全新的对象。
    拷贝的目的:产生一个副本对象,跟源对象互不影响,修改了源对象,不会影响副本对象,修改了副本对象,不会影响源对象。
    
    mian {
    NSString *str1 = [[NSString alloc] initWithFormat:@"test11111111111111111"];
    NSString *str2 = [str1 copy]; //相当于调用retain 浅拷贝,指针拷贝,没有产生新对象。
    NSString *str3 = [str1 mutableCopy]; //深拷贝:内容拷贝,有产生新对象。
    [str3 release];
    [str2 release];
    [str1 release];
    }
    alloc、new、copy、mutableCopy返回了一个对象,对应一个release和autorelease.
    
    mutableCopy拷贝出来的一定是可变对象。
    copy拷贝出来的一定是不可变对象。
    mutableCopy一定是深拷贝。
    copy原对象是不可变对象是浅拷贝,copy原对象是可变对象是深拷贝。
    
    10.copy的实现原理?
    @property (nonatomic,copy) NSArray *array; //copy->右边一定是不可变
    //@property (nonatomic,copy) NSMutableArray *array //是错误的 会崩溃
    - (void)setData:(NSArray *)data {
               if (_data != data) {
        `                [ _data release];
                         _data = [data copy];
                }
    }
    
    NSString为什么要用copy?可以从UI层面解释。
    (copy) text
    NSMutableString *str = [NSMutableString @'123'];
    textField.text = str;
    防止修改str的值textField.text 的值会发生变化。
    
    一般情况下:
    @property (nonatomic,strong) NSArray *array;
    @property (nonatomic,copy) NSString *str;
    
    11.自定义copy 实现原理
    遵循NSCopying协议,实现- (id)copyWithZone:(nullable NSZone *)zone 方法。
    
    .h
    @interface Person : NSObject<NSCopying>
    .m
    - (id)copyWithZone:(nullable NSZone *)zone {
        Person *person = [[Person alloc]init];
        person.age = self.age;
        person.weight = self.weight;
        return person;
    }
    
    12.ARC帮我们做了什么?是llvm编译器和Runtime系统协作的结果。
    __strong MJPerson *person1;
        __weak MJPerson *person2;
        __unsafe_unretained MJPerson *person3;
        NSLog(@"111");
        {
            MJPerson *person = [[MJPerson alloc] init];
            person3 = person;
        }
        NSLog(@"222 - %@", person3);
    
    大括号结束llvm帮我们生成release代码。
    程序运行时大括号结束person对象释放,Runtime清除当前对象person的弱引用指针。
    
    13.weak指针实现原理?
    当大口号结束时,person对象释放,会调用dealloc->rootdealloc系列调用,根据当前对象指针找到其在弱引用表中的索引,再将指向当前对象的所有弱引用指针全部清除。
    
    14.extern如何使用?在类外部声明私有变量、方法,即可访问。
    extern void person_test(void);
    main() {
            person_test();
    }
    
    Person.h  person_test不在这里声明
    Person.m
    void person_test(){
        NSLog(@"person - test");
    }
    
    15.autoreleasepool实现原理?从结构、push、autorelease、pop四方面去回答
    底层数据结构:_AtAutoreleasePool、AutoreleasePoolPage
    AutoreleasePoolPage管理autorelease对象
    class AutoreleasePoolPage {
          pthread_t const thread;
          id *next; //指向下一个能存放autorelease对象的地址的内存区域
          AutoreleasePoolPage *const parent;
          AutoreleasePoolPage *child;
    }
    
    调用push方法会将一个POOL_BOUNDARY入栈,并且返回其存放的内存地址。
    调用autorelease的对象都会入栈;
    调用pop方法时传入一个POOL_BOUNDARY的内存地址,会从最后一个入栈的对象开始发送release消息,直到遇到这个POOL_BOUNDARY
    
    16.autorelease对象在什么时机会被调用release?分2种情况。大括号结束,休眠前,退出runloop时候。
    第1种情况
    是由runloop来控制的,,它可能是在某次runloop循环中runloop休眠之前调用的。
    viewdidload {
          Person *person = [[[Person alloc] init] autorelease];
    }
    
    第2种情况
    viewdidload {
          @autoreleasepool{
                      Person *person = [[[Person alloc] init] autorelease];
            }//在这里释放
    }
    
    iOS在主线程的Runloop中注册了2个Observer
    第1个Observer监听了kCFRunLoopEntry事件,会调用objc_autoreleasePoolPush()
    第2个Observer
    监听了kCFRunLoopBeforeWaiting事件,会调用objc_autoreleasePoolPop()、objc_autoreleasePoolPush()
    监听了kCFRunLoopBeforeExit事件,会调用objc_autoreleasePoolPop()
    
    14.方法里有局部对象,出了方法后会立即释放吗?2中情况。由编译器生成的release、autorelease决定。
    viewdidload {
          Person *person = [[Person alloc] init];
    }
    (1)如果编译器 Person *person = [[Person alloc] init];在这里立刻生成了autorelease方法的话,可能是在某次runloop循环中runloop休眠之前释放的。
    (2)如果是在方法结束之前生成了[person release]则是在方法结束后
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    

    相关文章

      网友评论

          本文标题:内存管理

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