【IOS学习基础】内存管理

1、内存几大区域

1> 栈区:局部变量(基本数据类型、指针变量)。
2> 堆区:程序运行的过程中动态分配的存储空间(创建的对象)。
3> BSS段:没有初始化的全局变量和静态变量。
4> 数据区:已经初始化的全局变量和静态变量。(字符串常量)
5> 代码段:程序编译后的代码的内容。

 

2、引用计数器

1> 引用计数器:每个继承自NSObject的对象都有一个引用计数器,用来表示当前对象有几个拥有者。
2> 引用计数器的作用:用来判断对象是否应该回收。
3> 引用计数器的操作(ARC下无法使用)
 * retain  引用计数器+1
 release  引用计数器-1 
 retainCount 得到引用计数器的值(点击进入NSObject.h文件,有一个 - (NSUInteger)retainCount OBJC_ARC_UNAVAILABLE 的方法)
 注:任何一个OC对象,只要一被创建出来,其引用计数默认为1;一个对象的引用计数归0的时候,对象就会被销毁。

 

3、关于dealloc方法

1> 对象被释放时会自动调用
2> 开发中经常重写对象的dealloc方法,用于观察对象什么时候被释放或者想要在对象释放之前做些相应的操作,dealloc方法可以看做是对象的“临终遗言”。
3> 在MRC下,重写dealloc要注意必须要在其最后调用[super dealloc]

 

4、僵尸对象、野指针、空指针。

1> 僵尸对象:即指已经被销毁的对象(不能再使用的对象)
2> 野指针:指向僵尸对象(不可用内存)的指针,给野指针发送消息会报“EXC_BAD_ACCESS"错误(常见错误)。
3> 空指针:没有指向存储空间的指针(nil),给空指针发送消息没有任何反应,试想一下,用nil调用方法怎么可能有反应。而解决野指针错误的方法就是将对象的指针变为空指针。
// 先开启僵尸对象检测
        
 NSObject *obj = [[NSObject alloc] init];  
 [obj release];      
 // 野指针错误
[obj log:@"测试"];


// 输出台打印
2016-01-21 19:35:46.367 内存管理[2688:205046] *** -[NSObject log:]: message sent to deallocated instance 0x100113c80 (向一个已经被释放的实例对象发送了消息)

 

5、开发中关于ARC(自动内存管理)和MRC(手动内存管理)的常用操作

1> 将工程从ARC环境改为MRC环境(现在基本上都是ARC环境,保持默认即可)
搜索框中输入“auto”
将“YES”改为“NO”,即从ARC改为MRC了,反之改为“YES“就是从MRC改为ARC
 
2> 工程总体环境是ARC的,让工程中某个类支持MRC
开发中,我们有时候可能用到一些以前的类,而有些比较老的类库又是MRC环境的,那么可以选择增加编译开关"-fno-objc-arc”(这里以GDataXMLNode类为例)
除了关于“libxml.dylib”动态库错之外,初次将GDataXMLNode导入工程的时候,会出现大约二十个错误,按照如下图操作即可
  
 
3> 检测野指针(僵尸对象)错误
   
 

6、关于nil、Nil、NULL

1> nil是一个对象值(对象为空)  将对象等于nil。可以防止调用僵尸对象报错
2> Nil是一个类对象(类对象为空)
3> NULL是一个通用指针(泛型指针)
4> [NSNull null]是一个对象,用在不能使用nil的场合。
 

7、@property参数

1> 控制set方法的内存管理
  retain : release旧值,retain新值(用于OC对象)
  assign : 直接赋值,不做任何内存管理(默认,用于非OC对象类型)
  copy   : release旧值,copy新值(一般用于NSString,保证字符串的安全性)
 
2> 控制需不需生成set方法
  readwrite :同时生成set方法和get方法(默认)
  readonly  :只会生成get方法
  
3> 多线程管理
  atomic    :性能低(默认)
  nonatomic :性能高
 
4> 控制set方法和get方法的名称
  setter : 设置set方法的名称,一定有个冒号:
  getter : 设置get方法的名称
 

8、NSString在内存管理中的问题

// 最近在网上视频上看到的一个有趣的问题,按照视频上所讲
        
// 字符串有一个常量池
// 如果你需要的字符串在常量池中已经存在了,不会分配内存空间
// 使用字符串的时候:采用下面1、3、5方式获取的字符串都在常量区(嗯,这三个NSString对象跟视频上讲的一样,确实在字符常量区,因为打印其引用计数是一个巨大的数,所以判断其内存不归用户管)
        
// 注意:视频上所讲,str2和str4的应该被分配在堆区,即内存归用户管,引用计数应该为1
// 但事实上,看下面打印的str2和str4?瞬间凌乱了,Why,说好的在堆区呢?
     
        NSString *str1 = @"abc";
        NSString *str2 = [NSString stringWithFormat:@"aaa"];
        NSString *str3 = [NSString stringWithString:@"abc"];
        NSString *str4 = [[NSString alloc] initWithFormat:@"aaa"];
        NSString *str5 = [[NSString alloc] initWithString:@"abc"];
        NSString *str6 = [[NSString alloc] init];  // 在栈区?为啥它的引用计数那么大?
        NSLog(@"str1 = %@ , %p , %lu",str1,str1,str1.retainCount);
        NSLog(@"str2 = %@ , %p , %lu",str2,str2,str2.retainCount);
        NSLog(@"str3 = %@ , %p , %lu",str3,str3,str3.retainCount);
        NSLog(@"str4 = %@ , %p , %lu",str4,str4,str4.retainCount);
        NSLog(@"str5 = %@ , %p , %lu",str5,str5,str4.retainCount);
        NSLog(@"str6 = %@ , %p , %lu",str6,str6,str5.retainCount);

// 打印

  2016-01-21 21:26:36.979 NSString内存管理问题[3269:255674] str1 = abc , 0x100004230 , 18446744073709551615

  2016-01-21 21:26:36.980 NSString内存管理问题[3269:255674] str2 = aaa , 0x61616135 , 18446744073709551615

  2016-01-21 21:26:36.981 NSString内存管理问题[3269:255674] str3 = abc , 0x100004230 , 18446744073709551615

  2016-01-21 21:26:36.981 NSString内存管理问题[3269:255674] str4 = aaa , 0x61616135 , 18446744073709551615

  2016-01-21 21:26:36.981 NSString内存管理问题[3269:255674] str5 = abc , 0x100004230 , 18446744073709551615

  2016-01-21 21:26:36.981 NSString内存管理问题[3269:255674] str6 =  , 0x7fff7c51bd00 , 18446744073709551615

  // 然后说在IOS项目下又不一样,我姑且又试了一试,确实是内存地址不一样了,但是引用计数是什么鬼

  2016-01-21 21:30:42.632 NSString内存管理[3289:257683] str1 = abc , 0x106f4c050 , 18446744073709551615

  2016-01-21 21:30:42.633 NSString内存管理[3289:257683] str2 = aaa , 0xa000000006161613 , 18446744073709551615

  2016-01-21 21:30:42.633 NSString内存管理[3289:257683] str3 = abc , 0x106f4c050 , 18446744073709551615

  2016-01-21 21:30:42.633 NSString内存管理[3289:257683] str4 = aaa , 0xa000000006161613 , 18446744073709551615

  2016-01-21 21:30:42.633 NSString内存管理[3289:257683] str5 = abc , 0x106f4c050 , 18446744073709551615

  2016-01-21 21:30:42.633 NSString内存管理[3289:257683] str6 =  , 0x107279380 , 18446744073709551615

  // 最后,我不死心,又试了一下

  NSArray *array1 = [[NSArray alloc] init];

  NSLog(@"array1 = %lu",array1.retainCount);

  NSMutableArray *array2 = [[NSMutableArray alloc] init];

  NSLog(@"array2 = %lu",array2.retainCount);

 // 打印 

  2016-01-21 21:48:01.828 NSString内存管理问题[3447:267148] array1 = 2  // 妈蛋  为什么是2

  2016-01-21 21:48:01.828 NSString内存管理问题[3447:267148] array2 = 1

 // 最后

  看到最后,有这么一张图

  

    总结一下吧,不要相信retainCount的值。(不要用它去做判断)

  平常都在用ARC,也没注意到有这些问题,既然看到了,就权当了解一下。

  
  
好记性不如烂笔头!多多复习基础知识,一一记录下来还是有所收获的! 
 
posted @ 2016-01-21 20:44  不忘、初心  阅读(759)  评论(0编辑  收藏  举报