标签:
回顾堆栈的区别 生命周期
栈空间 函数 函数中局部变量 调用函数压栈 函数调用结束 释放
数据段 静态变量 全局变量 程序开始 程序结束 释放
堆: malloc alloc 程序猿手动释放 free() release
内存管理就是确保开辟的堆空间被正确的释放。
内存管理中的问题:
1 Person * p = [[Person alloc] init];
2 NSLog(@"%lu",p.retainCount);
3 // [p retain];
4 Person * q = [p retain];
5 NSLog(@"%lu",q.retainCount);
6
7 [p release];
8 NSLog(@"%lu",p.retainCount);
9
10 [q release];
11 NSLog(@"%lu",p.retainCount);
12 [p run];
创建一个Person类 一个p指针指向创建的对象 创建完成之后 计数器为1 创建一个q指针指向p原本指的对象 计数器+1为2
[p release] 计数器-1 [q release] 计数器再-1 此时对象释放
1 - (void)dealloc {
2 NSLog(@"人被释放了");
3 [super dealloc];
4 }
类中重写dealloc方法 则会输出 人被释放了 若开启僵尸对象检测 则[p run]报错
// 为什么最后不为0?
最后一次输出,引用计数没有变成0.
这是为什么呢?
因为该对象的内存已经被回收,而我们向一个已经被回收的对象发了一个retainCount消息,所以它的输出结果应该是不确定的,如果该对象所占的内存被复用了,那么就有可能造成程序异常崩溃。
那为什么在这个对象被回收之后,这个不确定的值是1而不是0呢?这是因为当最后一次执行release时,系统知道马上就要回收内存了,就没有必要再将retainCount减1了,因为不管减不减1,该对象都肯定会被回收,而对象被回收后,它的所有的内存区域,包括retainCount值也变得没有意义。不将这个值从1变成0,可以减少一次内存操作,加速对象的回收。
1 Person * p = [[Person alloc] init];
2 NSLog(@"%lu",p.retainCount);
3 Person * q = [p retain];
4 NSLog(@"%lu",q.retainCount);
5 [p release];//引用两次需要两次release 少写一次都会内存泄露
6 [q release];
1 Person * p2 = [[Person alloc] init];
2 NSLog(@"%lu",p2.retainCount);
3 p2 = nil;
4 [p2 release]; // [nil release]
释放前指向nil 然后release 之前的对象没有被释放
1 Person * p = [[Person alloc] init];
2 NSLog(@"%lu",p.retainCount);
3 Person * q = [p retain];
4
5 [p release];
6 // p = nil;
7 [q release];
8 //q = nil;
9 [p run]; // [nil run] // nil 调用任何方法都不会报错
提前释放之后再用对象的方法 会形成提前释放的野指针
1 Person * p = [[Person alloc] init]; 2 NSLog(@"%lu",p.retainCount); 3 [p release]; 4 [p release]; 5 //重复释放
释放之后 不可retain 无法起死回生
1 // 创建Person对象
2 Person * p = [[Person alloc] init];
3 // 创建Car对象
4 Car * c = [[Car alloc] init];
5 // 让人有一辆车
6 [p setCar:c];
7 [p drive];
8 [c release];
9 [p drive];
10 // 只要p对象存在,就可以随意调用自己的方法
11 [p release];
1 //Car类成员方法的实现以及dealloc的重写
2 - (void)dealloc {
3 NSLog(@"dealloc 车被销毁了");
4 [super dealloc];
5 }
6
7 - (void)run {
8 NSLog(@"车跑起来了");
9 }
1 //Person类成员方法的实现以及dealloc方法的重写
2
3 - (void)setCar:(Car *)car {
4 //在setCar的时候,让car的retainCount+1
5 // 目的是保证p对象存在的时候,_car对象一定存在
6 _car = [car retain];
7 }
8
9 - (Car *)car {
10 return _car;
11 }
12
13 - (void)drive {
14 [_car run];
15 }
16
17 - (void)dealloc {
18 NSLog(@"dealloc 人被销毁了");
19 // 保证p对象销毁的时候,他所持有的_car对象也被销毁,防止出现内存泄露
20 [_car release];
21 [super dealloc];
22 }
若两次set方法的参数都为同一对象 那么会先把对象release一次之后再retain 但release之后就释放掉了 所以要判断参数是否和对象的成员相等
1 - (void)setCar:(Car *)car {
2 //在setCar的时候,让car的retainCount+1
3 // 目的是保证p对象存在的时候,_car对象一定存在
4
5 // 如果调用 _car = car,并且_car的retainCount=1 的情况下会出现野指针问题
6 if (_car != car) {
7 // 第一次运行 [nil release]
8 [_car release];
9 _car = [car retain];
10 }
11
12 }
set方法可以改写为如下所示。
// 1与内存管理相关的参数
// 默认是 assign
// retain 生成符合内存管理原则的set方法
// assign 直接赋值,不考虑内存管理(一般基本数据类型)
// 2 与多线程相关的代码
// notatomic 不生成与多线程相关的代码 默认 iOS开发中用这个
// atomic 生成与多线程相关的代码 mac开发中会用到
// 3 是否生成set与get方法
// readonly 只生成get方法
// readwrite 生成get与set方法 默认
// 没有只生成set方法的参数
// 4 set与get方法名称相关的参数
// setter 设置set方法的名字(有冒号);
// getter 设置get方法的名字
Person类有Car类的属性
Car类也有Person类的属性 就成为循环引用
.h文件中导入头文件应换成 @class 类名 的形式
前向声明 告诉系统有这样一个类
.m文件中应导入头文件 调用类的成员方法
引用关系应该一强一弱
1 #import <Foundation/Foundation.h>
2 #import "Person.h"
3 #import "Car.h"
4 int main(int argc, const char * argv[]) {
5 @autoreleasepool {
6 // p 1 car 1
7 Person * p = [[Person alloc] init];
8 Car * car = [[Car alloc] init];
9 // p 1 car 2
10 [p setCar:car];
11 // car 2 p 1
12 [car setPerson:p];
13 // p 0 car 1
14 [p release]; //难点总结:p release之后 计数count 变为0,此时调用 p 的 dealloc 函数,随之成员变量_car release
15 // p 0 car 0
16
17 [car release];
18
19
20
21
22 // // p 1 car 1
23 // Person * p = [[Person alloc] init];
24 // Car * car = [[Car alloc] init];
25 // // p 1 car 1
26 // [p setCar:car];
27 // // car 1 p 2
28 // [car setPerson:p];
29 // // p 1 car 1
30 // [p release];
31 // // p 0 car 0
32 // [car release];
33
34
35
36
37 // // p 1 car 1
38 // Person * p = [[Person alloc] init];
39 // Car * car = [[Car alloc] init];
40 // // p 1 car 2
41 // [p setCar:car];
42 // // car 2 p 2
43 // [car setPerson:p];
44 // // p 1 car 2
45 // [p release];
46 // // p 1 car 1
47 // [car release];
48
49 }
50 return 0;
51 }
1 #import <Foundation/Foundation.h>
2 @class Car; // 前向声明 告诉系统有这样一个类
3 @interface Person : NSObject
4 @property (nonatomic,retain) Car * car;
5 @end
1 #import "Person.h"
2 #import "Car.h"
3 @implementation Person
4 - (void)dealloc {
5 NSLog(@"person 被销毁了");
6 [_car release];
7 [super dealloc];
8 }
9 @end
1 #import <Foundation/Foundation.h>
2 @class Person;
3 @interface Car : NSObject
4 @property (nonatomic,assign) Person * person;
5 @end
1 #import "Car.h"
2 #import "Person.h"
3 @implementation Car
4 - (void)dealloc {
5 NSLog(@"car 被销毁了");
6 // [_person release]; 弱引用 所以没有这行
7 [super dealloc];
8 }
9 @end
未完待续。。。。。
标签:
原文地址:http://www.cnblogs.com/gwkiOS/p/4941360.html