• 内存管理知识点总结


    一、内存区域分类:

    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没有影响

             

     

  • 相关阅读:
    数组
    js--函数
    for循环
    运算符
    js 正则表达式
    js DOM节点
    js 字符串
    js 函数
    2018-12-26 课堂笔记 for循环
    2018-12-25 课堂笔记 js
  • 原文地址:https://www.cnblogs.com/ciciCassie/p/5789690.html
Copyright © 2020-2023  润新知