浅谈内存管理及僵尸对象

//--------------------内存管理

内存管理范围:

管理任何继承NSObject的对象,基本数据类型不需要内存管理。

对象类型是程序运行过程中动态分配的,存储在堆区,内存管理主要是对"堆区中的对象"进行内存管理。

//--------------------概念

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

任何对象都可能拥有一个或多个所有者。只要一个对象至少还拥有一个所有者,它就会继续存在

2)对象的引用计数器

每个OC对象都有自己的引用计数器,是一个整数表示对象被引用的次数,即现在有多少东西在使用这个对象。对象刚被创建时,默认计数器值为1,当计数器的值变为0时,则对象销毁。

在每个OC对象内部,都专门有8个字节的存储空间来存储引用计数器。

3)引用计数器的作用

判断对象要不要回收的唯一依据

(存在一种例外:对象值为nil时,引用计数为0,但不回收空间)就是计数器是否为0,若不为0则存在。

//----------------------对引用计数器的操作3个方法

给对象发送消息,进行相应的计数器操作。

retain消息:使计数器+1

release消息:使计数器-1(并不代表释放对象)

retainCount消息:获得对象当前的引用计数器值rc

//--------------------------对象的销毁

当一个对象的引用计数器为0时,那么它将被销毁,其占用的内存被系统回收。

//1.对象销毁就自动执行dealloc方法

当对象被销毁时,系统会自动向对象发送一条dealloc消息,一般会重写dealloc方法,在这里释放相关的资源,dealloc就像是对象的"临终遗言"。

//2.重写dealloc方法

一旦重写了dealloc方法就必须调用[superdealloc],并且放在代码块的最后调用(不能直接调用dealloc方法)。

//3.对象销毁了存储空间不可用

一旦对象被回收了,那么他所占据的存储空间就不再可用,坚持使用会导致程序崩溃(野指针错误)。

#注意:

1)如果对象的计数器不为0,那么在整个程序运行过程,它占用的内存就不可能被回收(除非整个程序已经退出)

2)任何一个对象,刚生下来的时候,引用计数器都为1。(对象一旦创建好,默认引用计数器就是1  )

3)当使用"alloc"、"new"或者"copy"("mutablecopy")创建一个对象时,对象的引用计数器默认就是1 ;

对应的方法:

-retain         +1

-release        -1

-retainCount当前引用技数为多少0 --->系统释放这个对象

-dealloc

#warning开放如何使用:需要理解MRC,但实际使用时尽量用ARC

//------------------------MRC

target   Build Settings   Basic   Leveis搜索auto-->NO

内存管理的关键是"如何判断对象被回收"

问题:

1.对象创建完之后默认引用计数是多少?      1

2.当对象的引用计数为多少?     0系统就会回收这个对象的空间

3.怎么知道这个对象空间被释放了?

重写dealloc方法在dealloc方法中打印以下信息

-------------------关于dealloc方法

代码规范:

(1)一定要[superdealloc],而且要放到最后,意义是:"先释放子类占用的空间再释放父类占用的空间"

(2)对self(当前)所拥有的的其他对象做一次release操作

-(void)dealloc

{

//先释放子类拥有的对象属性

[superdealloc];

}

注意:

永远不要直接通过对象调用dealloc方法(对象的引用计数为0系统会自动调用此方法)

-------------------------------------

原则

1.只要还有人在使用某个对象,那么这个对象就不会被回收;

2.只要你想使用这个对象,那么就应该让这个对象的引用计数器+1;

3.当你不想使用这个对象时,应该让对象的引用计数器-1;

记住两点:

1,谁创建"alloc","new",谁"release";

2,谁"retain",谁"release";

正确的手动管理操作:

一个alloc/new对应一个release

一个retain对应一个release

总结

有始有终,有加就应该有减,曾经让某个对象计数器加1,就应该让其在最后减1;

//---------------------僵尸对象与内存泄露

区分以下2个概念:

1)"僵尸对象"(野指针)(没有初始化的指针变量;指向的内存空间已经被释放的指针变量)

栈区,系统会自动管理

//空指针:没有指向任何东西的指针,给空指针发送消息不会报错对象= nil

2)"内存泄露"(栈区的指向已经释放,堆区的空间没有释放,这时堆区的空间就被泄露了)

堆区,需要程序员手动管理

#不管是多个对象还是单个对象,只要我们研究它的内存管理,就两点:

#1.僵尸对象(野指针)

#2.内存泄露

//---------------------------关于僵尸对象问题

首先什么是僵尸对象:

"僵尸对象"(野指针)(没有初始化的指针变量;指向的内存空间已经被释放的指针变量)

栈区,系统会自动管理

#检测野指针

(检测僵尸对象,比较耗费性能,所以Xcode默认是不检测的)

打开方法:

Edit Scheme  -->  Run Debug   --->  Diagnostics  -->  Enable Zombie Objects(打勾)

对象一旦成为了僵尸对象,就不能再使用这个僵尸对象了

#判断是否是僵尸对象:

person(对象)  -->看什么?

看是否执行了dealloc方法--->重写dealloc方法打印一句话提醒

dealloc方法一旦调用了,意味着堆区的空间已经被释放,释放就意味着这个对象是僵尸对象

#避免使用僵尸对象的方法

1)僵尸对象调用方法,会报错,访问成员变量有时是可以的(但是这个是未知的)。

2)为了防止不小心调用了僵尸对象,可以将对象赋值nil(对象的空值)

用nil调用方法是不会报错的。

#关键:

3)总而言之要合理使用release和retain

//-----------------nil和Nil及NULL、NSNull的区别:

了解:

1.nil对象的值person =nil;

2.Nil类对象的值

3.NULLC语言的关键字通用空指针

4.  NSNull空对象用在不能使用nil的地方

//---------------------------关于内存泄露问题

首先:

什么是内存泄露:

"内存泄露"(栈区的指向已经释放,堆区的空间没有释放,这时堆区的空间就被泄露了)

堆区,需要程序员手动管理

#对象的内存泄露的几种情况

1) retain和release不匹配,retain多余release导致的内存泄露;

2)对象使用过程中,没有被release,而被赋值为nil;

3)在方法中不当的使用了retain;

#关键:

3)总而言之要合理使用release和retain

还是记住两点:

1.谁创建"alloc","new",谁"release";

2.谁"retain",谁"release";

内存管理的验证:

1.查看retainCount的值

2.重写dealloc方法,查看对象是否调用了dealloc方法

/*

一个alloc/new对应一个release

一个retain对应一个release

*/

//-----------------------多对象的内存管理

#多个对象的僵尸对象问题

假设对象A与对象B有(关联)关系,如果对象B独自销毁,会影响对象A的操作.

{

Car *_car;

}

假设:person拥有车

{

//创建一个人对象rc = 1

Person *person = [Person new];

//创建一个车对象rc = 1

Car *car = [Car new];

//让人拥有这辆车

person.car = car;

//人调用开车这个方法

[person driver];

[car release];

#关键的地方在这里看这里!!

#    [person driver]不能再调用这个方法人是拥有车的,人都还没释放,就不能调用与car有关系的driver方法是不科学的

[person release];

}

#解决方案

1.在人的实例变量_car的set方法中set方法中[_car retain];     +1

2.在人的dealloc方法中先把自己拥有的对象先释放[_car release];  -1

总结:

凡事关联关系,对象A与对象B有(关联)关系,就应该在set方法中让关联的对象+1,然后在对象A的dealloc方法中让关联的对象-1.

//------------------------------------------------

#多个对象的内存泄露问题

问题:

就上面的解决方法,还是有弊端,会造成原对象泄露

比如说人中途换车了多次调用了关于_car的set方法导致_car多次retain而没有相对应的release方法,导致rc没变为0,对象没有释放,就说内存泄露了

1.人第"1"次使用set方法赋值第一次把byd赋值给人的_car

2.人第"2"次使用set方法赋值第二次把byd赋值给人的_car

3.人第"3"次使用set方法赋值第三次把bigben赋值给人的_car

1.byd(首次赋值)  _car =nil_car != bydif执行[_car release]由于_car是nil[nilrelease]赋值赋值之后_car retain    byd+1

2.byd(多次调用)  _car = byd  _car == bydif不执行

3.bigBen(换车)  _car = byd  car = bigBen  _car != carif执行[_car release] --> [byd release]赋值赋值指针bigBen retain   bigBen + 1

在dealloc方法中:

如果只执行了第1步或者第1第2步则:

[_car release];  _car (byd) release    -1

如果执行了第1,2,3步则:

[_car release];//  _car  ---> bigBen     -1

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

if(_car != car){//  _car != car           _car实例变量!=    car参数

[_car release];//先release旧值

_car = car;//赋新值_car = [car retain];

[_car retain];//再retain新值

}

#判断是否是同一个对象,release旧值,retain新值

}

-(void)dealloc{

//该对象在被释放之前,必须先把自己所拥有的对象释放,也就是release一次自己的实例变量(对象)

[_car release];

[superdealloc];

}

//----------------------------set方法内存管理

#基本数据类型: int float double long struct enum基本数据类型做实例变量,就正常写法

-(void)setAge:(int)age{

_age = age;

}

#对象类型:对于对象作为另一个类的实例变量

判断是否是同一个对象,release旧值,retain新值

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

if(_car != car){

[_car release];//先release旧值

_car = car;//赋新值

[_car retain];//再retain新值

}

}

//------------------------@property参数

@property帮我们生成get和set方法的声明和实现

#格式: @property (参数1,参数2)数据类型实例变量名(记住:此处不要带下划线)

#原子性:   (习惯不加锁)

"atomic":默认值,对属性加锁,多线程下线程安全

"nonatomic":对属性不加锁,多线程下不安全,但速度快

#读写属性: (用得不多)

"readwrite":默认值,生成getter,setter方法.

"readonly":只生成getter方法

#  setter方法的处理

1)基本数据类型或者C语言的构造类型:直接赋值

intfloatdoublelongstructenum等BOOL/ Boolean

"assign":@property的默认值,直接赋值

//如果使用assign  set方法就会生成如下代码

-(void)setAge:(int)age{

_age = age;

}

2)OC对象类型

"retain":先release原来的值,再retain新值

"copy":先release原来的值,再copy新值(NSString *)

//如果使用retain  set方法就会生成如下代码

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

if(_car != car){

[_car release];

_car = [car retain];

}

}

练习

{

Car *_car;

int_age;

enumSex _sex;

Dog *_dog;

NSString *_name;

}

@property(retain,nonatomic) Car *car;

@property(nonatomic,assign)intage;

@property(nonatomic,assign)enumSex sex;

@property(nonatomic,retain) Dog *dog;

@property(nonatomic,copy) NSString *name;

@property(nonatomic,assign,setter= setIsVip:,getter= haha)BOOLvip;

原方法名

-(void)setVip:(BOOL)vip;

-(BOOL)vip;

setter = setIsVip:,getter = haha

// setter=setIsVip:

// getter=haha方法名改了

如果使用中括号调用方法,要必须把方法名写正确了

如果使用点语法,就可以.实例变量名

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容

  • 29.理解引用计数 Objective-C语言使用引用计数来管理内存,也就是说,每个对象都有个可以递增或递减的计数...
    Code_Ninja阅读 1,470评论 1 3
  • 内存管理的原理? 内存空间总共有8块区域,有两个区域需要特别注意,一个就是堆空间,一个就是栈空间。栈里存放临时变量...
    Carden阅读 454评论 0 1
  • 内存管理的基本范围和概念. 程序运行过程中药创建大量的对象, 和其他高级语言类似,在ObjC中对象存储在堆区,程序...
    ValienZh阅读 867评论 0 2
  • 内存管理是程序在运行时分配内存、使用内存,并在程序完成时释放内存的过程。在Objective-C中,也被看作是在众...
    蹲瓜阅读 2,999评论 1 8
  • 连续写了两天比较专业,有一定深度的话题,今天我们来聊一些轻松的。小编记忆中那些能让你笑破肚皮的喜剧片。 《反斗神鹰...
    朱诚逸阅读 439评论 0 1