码迷,mamicode.com
首页 > 其他好文 > 详细

Objective-C内存管理

时间:2015-11-06 06:46:23      阅读:272      评论:0      收藏:0      [点我收藏+]

标签:

1.内存管理中的基本问题

  1.1为什么要进行内存管理    分配在堆空间中的对象 需要手动去释放

回顾堆栈的区别                                                                          生命周期 

栈空间    函数 函数中局部变量                   调用函数压栈    函数调用结束 释放  

数据段    静态变量  全局变量                      程序开始             程序结束 释放

堆:                malloc  alloc                                程序猿手动释放 free() release

 

  1.2内存管理的定义  

内存管理就是确保开辟的堆空间被正确的释放。

内存管理中的问题:

1.内存泄露  堆空间没有释放

2. 内存崩溃 野指针 (过早释放:使用已经释放的空间     

重复释放:重复释放同一个空间)

 

  1.3 C语言内存管理的缺陷

1 释放一个堆 ,必须保证所有使用堆的指针结束使用,避免(提前释放);

2  释放一个指针,确保指向同一个堆的指针,只有一个被释放,避免(重复释放);

3 模块化分工编程,不易明确谁来释放

4 多线程操作,不能确定哪个线程最后结束

 

  1.4 OC内存管理的基本原则

1.对象在完成创建的同时,内部会自动创建一个引用计数器,这个计数器,是系统用来判断是否回收对象的唯一依据,当我们的引用计数retainCount = 0的时候,系统会毫不犹豫回收当前对象

 2.[对象 retain]   reatinCount + 1 ,返回self

 3.[对象 release]  reatinCount - 1

 4.我们的引用计数retainCount = 0时  对象就被销毁了

  5.dealloc函数,当一个对象要被销毁的时候,系统会自动调用dealloc函数,通知对象你将要被销毁

  内存管理原则(配对原则):只要出现了 new,alloc,retain,就一定配对出现一个release,autorelease

 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,可以减少一次内存操作,加速对象的回收。

 

2.单个对象的内存管理

    2.1.1 内存泄露的第一种情况

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];

 2.1.2内存泄露的第二种情况

1     Person * p2 = [[Person alloc] init];
2     NSLog(@"%lu",p2.retainCount);
3     p2 = nil;
4     [p2 release]; // [nil release]

释放前指向nil   然后release 之前的对象没有被释放

 

  2.2.1 野指针的提前释放 

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 调用任何方法都不会报错

提前释放之后再用对象的方法 会形成提前释放的野指针

 

  2.2.2野指针的重复释放

1         Person * p = [[Person alloc] init];
2         NSLog(@"%lu",p.retainCount);        
3         [p release];
4         [p release];
5 //重复释放 

释放之后 不可retain  无法起死回生 

 

3.多个对象的内存管理

 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方法的内存管理  

若两次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方法可以改写为如下所示。

 

4.@property的参数

// 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方法的名字

 

5.循环引用问题

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 }
main.m
技术分享
1 #import <Foundation/Foundation.h>
2 @class Car; // 前向声明 告诉系统有这样一个类
3 @interface Person : NSObject
4 @property (nonatomic,retain) Car * car;
5 @end
Person.h
技术分享
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
Person.m
技术分享
1 #import <Foundation/Foundation.h>
2 @class Person;
3 @interface Car : NSObject
4 @property (nonatomic,assign) Person * person;
5 @end
Car.h
技术分享
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
Car.m

 

 

 

 

未完待续。。。。。

Objective-C内存管理

标签:

原文地址:http://www.cnblogs.com/gwkiOS/p/4941360.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!