设为首页 加入收藏

TOP

OC 知识:彻底理解 iOS 内存管理(MRC、ARC)(四)
2019-08-26 07:10:19 】 浏览:134
Tags:知识 彻底 理解 iOS 内存 管理 MRC ARC
ool drain]; @autoreleasepool {
// 创建一个自动释放池 Person *p = [[Person new] autorelease]; // 将代码写到这里就放入了自动释放池 } // 销毁自动释放池(会给池子中所有对象发送一条release消息)

5. autorelease的注意事项

  • 并不是放到自动释放池代码中,都会自动加入到自动释放池
@autoreleasepool {
    // 因为没有调用 autorelease 方法,所以对象没有加入到自动释放池
    Person *p = [[Person alloc] init];
    [p run];
}
  • 在自动释放池的外部发送autorelease 不会被加入到自动释放池中
    • autorelease是一个方法,只有在自动释 放池中调用才有效。
@autoreleasepool {
}
// 没有与之对应的自动释放池, 只有在自动释放池中调用autorelease才会放到释放池
Person *p = [[[Person alloc] init] autorelease];
[p run];

// 正确写法
@autoreleasepool {
    Person *p = [[[Person alloc] init] autorelease];
 }

// 正确写法
Person *p = [[Person alloc] init];
@autoreleasepool {
    [p autorelease];
}

6. 自动释放池的嵌套使用

  • 自动释放池是以栈的形式存在
  • 由于栈只有一个入口, 所以调用autorelease会将对象放到栈顶的自动释放池

栈顶就是离调用autorelease方法最近的自动释放池

@autoreleasepool { // 栈底自动释放池
    @autoreleasepool {
        @autoreleasepool { // 栈顶自动释放池
            Person *p = [[[Person alloc] init] autorelease];
        }
        Person *p = [[[Person alloc] init] autorelease];
    }
}
  • 自动释放池中不适宜放占用内存比较大的对象
    • 尽量避免对大内存使用该方法,对于这种延迟释放机制,还是尽量少用
    • 不要把大量循环操作放到同一个 @autoreleasepool 之间,这样会造成内存峰值的上升
// 内存暴涨
@autoreleasepool {
    for (int i = 0; i < 99999; ++i) {
        Person *p = [[[Person alloc] init] autorelease];
    }
}
// 内存不会暴涨
for (int i = 0; i < 99999; ++i) {
    @autoreleasepool {
        Person *p = [[[Person alloc] init] autorelease];
    }
}

7. autorelease错误用法

  • 不要连续调用autorelease
@autoreleasepool {
 // 错误写法, 过度释放
    Person *p = [[[[Person alloc] init] autorelease] autorelease];
 }
调用autorelease后又调用release(错误)
@autoreleasepool {
    Person *p = [[[Person alloc] init] autorelease];
    [p release]; // 错误写法, 过度释放
}

 

8. MRC中避免循环retain

定义两个类Person类和Dog类

  • Person类:
#import <Foundation/Foundation.h>
@class Dog;

@interface Person : NSObject
@property(nonatomic, retain)Dog *dog;
@end
  • Dog类:
#import <Foundation/Foundation.h>
@class Person;

@interface Dog : NSObject
@property(nonatomic, retain)Person *owner;
@end

执行以下代码:

int main(int argc, const char * argv[]) {
    Person *p = [Person new];
    Dog *d = [Dog new];

    p.dog = d; // retain
    d.owner = p; // retain  assign

    [p release];
    [d release];

    return 0;
}

就会出现A对象要拥有B对象,而B对应又要拥有A对象,此时会形成循环retain,导致A对象和B对象永远无法释放

那么如何解决这个问题呢?

  • 不要让A retain B,B retain A
  • 让其中一方不要做retain操作即可
  • 当两端互相引用时,应该一端用retain,一端用assign

4.ARC 自动管理内存(Automatic Reference Counting)

  • Automatic Reference Counting,自动引用计数,即ARC,WWDC2011和iOS5所引入的最大的变革和最激动人心的变化。ARC是新的LLVM 3.0编译器的一项特性,使用ARC,可以说一 举解决了广大iOS开发者所憎恨的手动内存管理的麻烦。
  • 使用ARC后,系统会检测出何时需要保持对象,何时需要自动释放对象,何时需要释放对象,编译器会管理好对象的内存,会在何时的地方插入retain, release和autorelease,通过生成正确的代码去自动释放或者保持对象。我们完全不用担心编译器会出错

1. ARC的判断原则

ARC判断一个对象是否需要释放不是通过引用计数来进行判断的,而是通过强指针来进行判断的。那么什么是强指针?

  • 强指针
    • 默认所有对象的指针变量都是强指针
    • 被__strong修饰的指针
 Person *p1 = [[Person alloc] init];
 __strong  Person *p2 = [[Person alloc] init];

 

  • 弱指针
    • 被__weak修饰的指针
__weak  Person *p = [[Person alloc] init];

ARC如何通过强指针来判断?

  • 只要还有一个强指针变量指向对象,对象就会保持在内存中

2. ARC的使用

int main(int argc, const char * argv[]) {
    // 不用写release, main函数执行完毕后p会被自动释放
    Person *p = [[Person alloc] init];
    return 0;
}

3. ARC的注意点

  • 不允许调用对象的 release方法
  • 不允许调用 autorelease方法
  • 重写父类的dealloc方法时,不能再调用 [super dealloc];

4. ARC下单对象内存管理

  • 局部变量释放对象随之被释放
    int main(int argc, const char * argv[]) {
       @autoreleasepool {
            Person *p =
首页 上一页 1 2 3 4 5 下一页 尾页 4/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇常用在线软件获取 下一篇BBWebImage 设计思路

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目