内存管理知识点总结

一、内存区域分类:

1、堆区:需要的时候系统会为你分配内存,但是系统不会自动回收,需要程序员手动释放内存

2、栈区:需要的时候系统会为你分配内存,不需要的时候系统自动回收该内存

3、常量区:存储常量,数据不能修改

4、全局,静态区:存储全局变量和静态变量

5、自由存储区

二、注意:

1、内存管理只针对继承NSObject的对象,对其他基本数据类型无效(int double NSRange等)

2、mac OS 有垃圾回收机制,但iOS没有,其内存管理需要开发者处理

3、内存管理的目的:保证每个对象在使用的时候存在内存中,不用的对象在最后从内存中清除

4、悬垂指针:如果在最后打印对象的retainCount应该为0,但因为悬垂指针结果会是1,所以retainCount仅仅作为参考,不能进行逻辑判断,可以在dealloc函数中添加一句输出语句来验证是否对象已经不存在

5、常量不需要内存管理,如果打印其retainCount为正无穷

6、要获取一个对象的持有权,引用计数必须加1,所以在初始化时要注意,不能用常规的,在MRC状态下,多个对象内存管理需要如下操作:

 1 - (void)setBook:(Book *)book {
 2     
 3     // 比较两个是否是同一个对象,所以用 !=
 4     if (_book != book) {  // 判断旧的和新的是否是同一个,如果是同一个,不需要释放,不操作
 5         
 6        [_book release];   // 当重新赋值的时候,走set方法,把之前的联系解除(释放旧的)
 7         
 8        _book = [book retain];    // 保证用户持有该对象 ---- 引用计数必须加1(持有新的)
 9         
10     }
11 }
12 
13 
14 // ----------------- 自定义初始化的方法 (不需要release,在dealloc里面释放) --------------
15 - (instancetype)initWithBook:(Book *)book andName:(NSString *)name {
16     self = [super init];
17     if (self) {
18         _book = [book retain]; // 保证持有
19         
20         _name = [name retain];;
21     }
22     return self;
23 }
24 
25 
26 #pragma mark - 便利构造
27 + (Person *)personWithBook:(Book *)book andName:(NSString *)name {
28     Person *per = [[Person alloc]initWithBook:book andName:name];
29     
30     return [per autorelease]; // 不能直接用release,因为那样无法返回
31 }

 

7、在类的实现文件中,必须包含dealloc方法:

// 当retainCount为0时,自动走该方法,无需自己调用   可以根据程序是否走该方法判断对象是否释放
- (void)dealloc {
    
    NSLog(@"person dealloc");
    
    [_book release];   // 在哪里持有,哪里释放,所以当person没有的时候,释放其持有
    // 上面也可以写成_book = nil; 效果相同
    
    [_name release];    // 属性 必须在dealloc中释放å
    
    [super dealloc];
}

 

8、集合中的内存管理

     某个对象加入到数组中,其retainCount + 1,不影响数组的retainCount

     数组的retainCount改变,不影响数组里面的元素的retainCount

     数组对象被销毁时,里面的对象元素,retainCount - 1 注意不是清零      示例代码如下:

Person *per = [[Person alloc]init];
        NSArray *array = [[NSArray alloc]initWithObjects:@"1", @"2", per, nil];
        
        NSLog(@"per = %lu, arr = %lu", per.retainCount, array.retainCount);
        
        [array retain];
        NSLog(@"per = %lu, arr = %lu", per.retainCount, array.retainCount);
        
        [array release];
        [array release];// 数组销毁的时候会使per的retainCount -1 ,所以下面只需要一次release
        [per release];

三、自动释放池

如果对象是在自动释放池中,则不需要release,因为在程序结束的时候,自动释放池会自己清除其里面的内容

 1 //        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
 2 //        [pool release];     被封装
 3         
 4         // 当pool release的时候,所有加autorelease的retainCount - 1
 5     
 6         Person *per = [[Person alloc]init];
 7         [per retain];
 8         [per autorelease];
 9         [per autorelease];
10 
11         NSLog(@"per = %lu", per.retainCount);
12         
13         NSArray *array = [[[NSArray alloc]initWithObjects:@"1", nil]autorelease];
14         // 等价于上面alloc + autorelease, 系统的便利构造方法不需要内存管理
15 
16         NSArray *array1 = [NSArray arrayWithObjects:@"2", nil];

四、循环引用:让其中一个引用变为弱引用(assign),在相互导入的时候,一个用@class,并在.m文件中用#import导入 示例如下:

 1 #import <Foundation/Foundation.h>
 2 
 3 @class Person;    // 互相引用的时候,防止循环引用  不能再.m文件中访问其属性和方法,所以要在.m 中import Person.h
 4 
 5 @interface Book : NSObject
 6 
 7 @property (nonatomic,assign) Person *per;   // 不会让引用计数加1,弱引用,打破平衡,让其中一个先减为0,才会进入dealloc
 8 
 9 
10 @end

四、其他错误总结:

ARC:

         1. retain(copy)  -- strong

         2. weak  修饰不需要持有的对象类型

 MRC: 

         不需要持有对象:assign

         需要持有对象:retain copy

 1         NSString *str = @"cassie";
 2 
 3         NSLog(@"常量:%lu", str.retainCount);
 4 
 5         NSString *str1 = [[NSString alloc]initWithFormat:@"你好"];
 6 
 7         [str1 release];             //   中文 -- 存在堆区,需要release
 8 
 9         NSLog(@"中文str:%lu", str1.retainCount);
10 
11 //      所以在用NSString类型的对象时,用release,防止内存泄露

谁持有谁释放(遵循原则)  错误示例及解释如下:

         NSArray *array = @[@"1"]; 相当于遍历构造 不需要释放

           1、混乱释放

                 Person * person = [[Person alloc] init];

                 Person * person1 = person;  person1 只是一个指针

                 [person1 release];// 不遵守内存管理原则,不持有person1,应该释放person

         2、内存泄露

                 Person * person1 = [[Person alloc] init];

                 Person * person2 = [[Person alloc] init];

                 person2 = person1;//指针指向发生改变,person2原有内存 泄露, 解决方案 autorelease

         3、过度释放

                 Person * person = [Person personWithName:@"tom" age:12];

                 [person release];//便利构造器初始化的对象,过度释放了,不需要release

         4nil对象的引用计数为0

                 Person * person = nil;

                 NSLog(@"%lu", [person retainCount]);

         5、常量对象的引用计数为无穷

                 NSString * name = @"name";

                 NSLog(@"%lu", [name retainCount]);

          常量型(英文 -- 在常量区)的字符串无需内存管理   release没有影响

         

 

 

posted @ 2016-08-20 09:50  Cassie语思菲菲  阅读(331)  评论(0编辑  收藏  举报