OC 底层原理笔记

24-内存管理之面试题

2020-02-11  本文已影响0人  zysmoon
一使用CADisplayLink、NSTimer有什么注意点?
二 介绍下内存的几大区域
三 讲一下你对 iOS 内存管理的理解
四 ARC 都帮我们做了什么?

首先利用LLVM,帮我们自动生成release,retain,autorelease代码
需要runtime运行时做一些事情
即ARC时LLVM编译器和Runtime系统相互协作的一个结果

五 weak指针的实现原理

将弱引用存储到一个哈希表里,当对象要销毁时,就会取出当前对象的弱引用表,将该表存储的弱引用都给清除掉

六 autorelease对象在什么时机会被调用release

iOS在主线程的Runloop中注册了2个Observer

代码例子如下

- (void)viewDidLoad {
    [super viewDidLoad];

    Person *person = [[Person alloc] init];
    NSLog(@"%s", __func__);
}

这个Person什么时候调用release,是由RunLoop来控制的
它可能是在某次RunLoop循环中,RunLoop休眠之前调用了release
Person *person = [[[Person alloc] init] autorelease];

6.1 包含在@autoreleasepool中,则在pop的时候,即@@autoreleasepool作用域结束的时候销毁。
七 方法里有局部对象, 出了方法后会立即释放吗
八 思考以下2段代码能发生什么事?有什么区别?
@property(nonatomic,strong)NSString *name;
// @property(nonatomic,copy)NSString *name;
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
for (int i = 0; i < 1000; i++) {
    dispatch_async(queue, ^{
        // 加锁
        self.name = [NSString stringWithFormat:@"abcdefghijk"];
        // 解锁
    });
}

运行结果

1653926-56fbc973f69fa62e.png

因为给self.name赋值,实际上是调用其set方法

- (void)setName:(NSString *)name {
    if (_name != name) {
        [_name release];
        _name = [name retain];
    }
}

set方法内部,会先执行release操作,然后再执行retain操作,如果是多个线程同时执行set方法,则会造成释放2次的情况,所有导致坏内存访问。

代码二

dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
for (int i = 0; i < 1000; i++) {
    dispatch_async(queue, ^{
        self.name = [NSString stringWithFormat:@"abc"];
    });
}

执行结果:正常访问没有奔溃报错。

NSString *str1 = [NSString stringWithFormat:@"abc"];
NSString *str2 = [NSString stringWithFormat:@"123abc11111111"];

NSLog(@"%@ %@", [str1 class], [str2 class]);
NSLog(@"%p %p", str1,str2);

运行结果

1653926-2cff43919b454d3e.png

因为一个是NSTaggedPointerString,一个是__NSCFString


本文参考:
路飞_Luck (https://www.jianshu.com/p/07f7b96bb03f)
以及借鉴MJ的教程视频
非常感谢.


上一篇 下一篇

猜你喜欢

热点阅读