黑马程序员--Objective-C内存管理我之见解

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體: 小  |  中  |  大  |  超大  

------<a href="http://www.itheima.com" target="blank">java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------

内存管理

为什么要进行内存管理?

因为设备的内存空间是有限的,如果一直占用,而不回收空间,内存就会被一直占用,导致内存不足, 系统就会就会报警,严重的可能直接退出程序,因此,在软件开发过程中,需要进行内存管理,以保证高效快速的分配内存,并且在适当的时候释放和回收内存资源。

内存管理的范围?

任何继承了NSObject的对象,对基本数据

类型无效,主要对堆区的内存进行管理。

为什么要对堆区的内存空间进行管理,基本数据类型不需要管理呢?

因为基本数据类型的数据会被放入栈中,他们依次紧密排列,遵循先进后出的原则,系统会自动进行管理。 而对象类型会被放到堆中,堆中的内存是不连续的,无法自动释放,所以需要我们管理。

内存管理的原理?

(1)对象的所有权及引用计数器

对象的所有权:任何对象都有一个或多个拥有者,只要一个对象至少还有一个拥有者,他就不会被释放

(2) 任何自己创建的对象都归自己所有,可以使用alloc和new开头或名字中包含copy的方法创建对象,使用return来获得一个对象的所有权。

(3) OC中都有专门8个字节的存储空间来存储引用计数器,用整数表示对象被引用的次数。

引用计数器是判断对象是否回收内存空间的依据。

(4) 给对象发送消息

return 计数器+1,方法返回对象本身

release 计数器-1,但不代表释放,autorelease 也可使引用计数器-1.

retaincount消息 用来获得当前引用计数器的值

引用计数器为0,系统像对象发送dealloc消息,(调用[super dealloc]方法,一定要写在后面)释放相关资源,对象被回收后将不能在被使用(僵尸对象),僵尸对象不可复活,否则会导致程序崩溃,导致野指针错误

如何防止野指针错误,在对象被释放后赋值为nil.

内存管理的分类?

MRC 手动内存管理

ARC 自动内存管理

垃圾回收 iOS不支持

内存管理的原则?

如果还有人使用某个对象,这个对象就不会被回收。

如果有人想使用这个对象 那么就应给让对象的引用计数器+1

如果不想使用这个对象,就有那个该让对象的引用计数器-1

谁创建谁relesase 谁retain 谁release.有始有终 有加有减。

内存研究的内容?

野指针 内存泄露

野指针 定义的指针变量没有初始化。指向的空间已经被释放

内存泄露 :如果栈区的的空间已经被释放了,而堆区的空间还没与被释放,堆区的空间就被泄露了。

单个对象内存管理

1. 野指针错误:

访问了一块坏的内存

2. 僵尸对象:

如果一个对象已经被释放,这个对象被称为僵尸对象

3. 空指针:

没有指向任何东西的指针,给空指针发送消息不会报错

4. nil和NULL的区别

nil 对象指针

NULL 类对象指针

5. 避免使用僵尸对象的方法:

对象释放了以后,给对象赋值为nil

6. 单个对象的内存泄露

情况1: 创建完成,使用之后,没有release

情况2: 没有遵守内存管理原则

Dog *d = [[Dog alloc] init]

[d retain];

情况3: 不当的使用了nil

Dog *d = [[Dog alloc] init]

d = nil;

情况4: 在方法中对传入的对象进行了retain

Dog *d = [[Dog alloc] init]

[d compareColorWithOther: d];

基本数据类型set方法的写法 直接赋值

-(void)setSpeed:(int)speed

{

_speed = speed;

}

对于对象作为另外一个类的实例变量

-(void)setDog:(Dog *)dog{

if(_dog!=dog){ //先判断是不是原来的对象

[_dog release]; //不是原来的对象做一次release,

_dog = [dog retain];

}

}

@PRoperty 参数

格式:@property (参数1,参数2) 数据类型 方法名

1.是否要生成set方法

readwrite : 同时生成setter和getter的声明、实现

readonly :只会生成getter的声明和实现

2.多线程管理

nonatomic :性能高(一般用这个)

atomic :性能低(默认)

3.set管理相关参数

retain :release旧值,return新值(适用于oc对象类型)

assign : 直接赋值(默认,适用于非OC对象)

copy : release旧值,copy新值

(1) assign 直接赋值

-(void)setCar:(Car *)car{

_car =car;

}

(2) retain release旧值,再retain新值

在一个类中有关联其他对象的时候,这个对象的 @property(nonatomic,assign) 数据类型 方法名

-(void)setCar:(Car *)car{

if(_car!=car){ //先判断是不是原来的对象

[_car release]; //不是原来的对象做一次release,

_car = [car retain];

}

}

(3) 是否要生成set方法(若只读,则不生成)

readonly :只读,只会生成getter的声明和实现

readwrite:默认的,同时生成setter和getter的声明和实现

(4)多线程管理

@property(nonatomic,assign) 数据类型 方法名

高性能,一般使用nonatomic

(5) set和get方法的名称

修改set和get方法的名称,主要用于布尔类型。因为返回布尔类型的方法名一般以is开头,修改名称一般用 在布尔类型中的getter

//替换set方法名称 @property(nonatomic,assign ,setter= isVip:)

//替换get方法名称 @property(nonatomic,assign ,getter = isVip)

//替换set,get方法名称 @property(nonatomic,assign ,setter=isVip,getter = isVip:)

循环retain问题

会导致两个对象都会内存泄露

防止方法:

1) 让某一个对象多释放一次(注意顺序)

2) 推荐方法: 一端使用assign 一端使用retain

Dog.h

#import <Foundation/Foundation.h>

//#import "Person.h"

@class Person;

@interface Dog : NSObject

//狗有个主人

@property (nonatomic,retain) Person *owner;//这里用retain

@end

Dog.m

#import "Dog.h"

#import "Person.h"

@implementation Dog

- (void)dealloc

{

[_owner release]; //

NSLog(@"Dog dealloc");

[super dealloc];

}

@end

Person.h

#import <Foundation/Foundation.h>

//#import "Dog.h"

@class Dog;

@interface Person : NSObject

//人拥有一条狗

@property (nonatomic,assign) Dog *dog;//这里用assign

@end

Person.m

#import "Person.h"

#import "Dog.h"

@implementation Person

- (void)dealloc

{

// [_dog release]; //nil这里不在需要

NSLog(@"Person dealloc");

[super dealloc];

}

@end

main.m

#import <Foundation/Foundation.h>

#import "Dog.h"

#import "Person.h"

int main(int argc, const char * argv[]) {

@autoreleasepool {

Person *p = [Person new]; //1

Dog *d = [Dog new]; //1

//人有一条狗

p.dog = d; // d 1

d.owner = p; // p 2

[p release]; //0

[d release]; //

// [d release];

// [p release];

}

return 0;

}

类方法不需要管理内存

autorelease基本使用

一个对象调用autorelease,将这个对象放到位于栈顶得的释放池

@autoreleasepool

{ //

}

概念介绍: 一种支持引用计数器的内存管理方式,可以暂时保存某个对象,然后再内存池自己的排干的时候对其中的每个对象发送release消息

好处: 不用担心对象释放时间,也不用担心什么时候调用release

原理:

autorelease实质上只是把对release的调用延迟了,对于每一个autorelease,该Object放入了当前的Autoreleasepool中,当该pool释放时,该pool中的所有Object都会被调用release;

自动释放池: 特殊的栈结构(数据结构),和内存的栈区结构不同

特点: 对象可以加入到自动释放池中,自动释放池结束的时候,会给释放池中的每个对象发送一条release消息

使用:

1)自动创建释放池

autoreleasepool{

}

2)加入自动释放池,

在自动释放池中

[对象 autorelease]

加入到自动释放池中以后,引用计数器不会变化

基本用法总结

1.会将对象放到一个自动释放池中

2.当自动释放池被销毁时,会对尺子里的所有对象做一次release操作

3.会返回对象本身

4.调用完autorelease方法后,对象的计数器不变。

int main(int argc, const char * argv[]) {

//1 创建自动释放池

Person *p = [Person new]; // p 1

@autoreleasepool {//自动释放池开始

[p run];

NSLog(@"%lu",p.retainCount); // 1

// [p autorelease] 把对象p加入到自动释放池中

// 注意:加入到自动释放池中以后, 引用计数不会变化

[p autorelease]; //加入自动释放池,

NSLog(@"%lu",p.retainCount); // 1

[p run];

}//自动释放池结束 [p release];

[p run];

return 0;

}

注意及错误用法:

1)并不是放到自动释放池中的代码产生的对象就会自动释放,如果需要释放,必须自动加入到自动释放池

2)如果对象调用了autorelease但是调用autorelease的时候,没有在任何一个自动释放池中,此时该对象也不会被加入到自动释放池

3)我们只需要在自动释放池代码块中调用autorelease就可以把对象加入到自动释放池

4)内存较大尽量不要使用autorelease

自动释放池嵌套使用

为什么内存管理只管理内存对象?

堆中内存不连续,无法自动释放!

我们如何对内存对象进行管理!

通过操作对象的引用计数器

autorelease的应用场景

经常用来在类方法中快速创建一个对象

ARC

指针分类

(1)强指针:默认情况下所有指针都是强指针 关键字__strong

(2)弱指针:__weak关键字修饰的指针

原则 :当开启ARC时,编译器将自动在代码合适的地方插入retain、release、autorelease.

永远不要写retain、release、autorelease;

判断准则:只要没有强指针,对象就会被释放

ARC机制:

1)判断是否是ARC机制

查看项目信息,不能使用retain release和autorelease,retainCount ,不能调用[super dealloc]

2)使用

正常创建对象,不用手动释放对象

ARC下单对象内存管理

ARC机制下,对象没有被强指针指向,对象会立即释放空间

(两个下划线)__strong 修饰的指针是强指针,可以不写

__weak 修饰的指针是弱指针

1) 强指针指向了其他内容,对于对象来说就没有强指针指向了

2) 弱指针赋值为nil

ARC下多对象的内存管理

ARC机制下不能使用retain 应该使用strong 和 weak

ARC下循环引用问题

循环引用时一端使用strong , 一端使用weak.

ARC下set方法内存和@property参数

原子性/读写 和MRC下一样

MRC ARC

assign assign 适用于非oc对象

retain strong(强指针) OC的其他对象 weak (成员变量是弱指针适用于oc对象)

copy copy

ARC使用特点及注意事项

特点:

1) 不允许调用retain release、retainCount

2) 允许重写dealloc,但是不能调用[super dealloc]

注意事项:

1)ARC中,只要弱指针对象不存在,直接把弱指针清空(赋值nil)操作

2)__weak Person *p = [Person new]

弱指针指向空间销毁过程: (1)释放对象空间 (2)指针赋值nil

MRC转换为ARC

edit->Refactor->convert to Objective-C ARC…简单代码

ARC兼容非ARC的类

转变为非ARC -fno-objc-arc

转变为ARC的 -f-objc-arc

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航