一、为什么要进行内存管理

系统资源有限,iOS会为每一个执行的程序分配30M的内存,超过20M会收到内存警告,超过30M将会终止应用程序。因此,要及时回收一些不须要再继续使用的内存空间,比方回收一些不再使用的对象和变量等,以保证应用程序能正常执行。

二、须要管理的内存

应用程序在执行过程中。会占用一定栈空间和堆空间,也就是说。应用程序执行过程中的数据,有的是放在栈中,有的是放在堆中。

栈中的数据由系统维护,无需开发者来管理,而堆中的数据须要程序猿来维护。

堆空间由开发者请求分配的。比方开发者发送一条alloc消息创建一个对象,实际上就向堆空间申请了一块内存,用于存储创建的对象。对象存储于堆中,当代码块结束时,这个代码块中涉及的全部局部变量会被回收。指向对象的指针也被回收。此时对象已经没有指针指向,若对象依旧存在于内存中,就会造成内存泄露。

在这里须要注意两点:

(1)基本数据类型一般放在栈中,不须要进行内存管理;

(2)创建对象时,指向对象的指针放在栈中。由系统维护。而指针指向的对象,则是放在堆中,须要开发者维护。

三、对象的结构与内存管理机制

1、C和C++内存管理的不足

在C和C++中,若有3个指针指向同一个对象,不论什么一个指针调用了free方法释放内存,其余的引用在不知道的情况下继续使用这块内存的时候,就会出现故障。

因此,何时由谁去释放这块内存,这就是C和C++在内存管理上的混乱。

2、OC在内存管理方面的完好

OC中引入了计数器和全部权的概念。

对象除了有自己的成员和方法外。还从NSObject类继承了一个保留计数器,又称引用计数器(retainCount)。每个OC对象都有一个4个字节的retainCount的计数器,表示当前对象被引用的计数。假设对象的计数变为0时,系统就会调用对象的dealloc方法,真正释放这个对象。

wx_fmt=jpeg&wxfrom=5&wx_lazy=1" alt="" style="width:auto!important; visibility:visible!important; height:auto!important">

3、引用计数器的使用

引用计数器工作机制:

(1)对象知道自己当前被引用的次数。

(2)最初创建对象时,对象的计数器为1。

(3)假设须要引用(持有)对象。能够给对象发送一个retain消息,对象的引用计数器加1。

(4)当不须要引用对象了。能够给对象发送release消息。这样对象的引用计数器就减1。

(5)当对象的引用计数器为1时,再给对象发送一条release消息,引用计数器减1。并自己主动调用对象的dealloc函数。销毁对象。

(6)计数器为0的对象不能再使用release或试图发送retain消息复活对象,那样会引起程序崩溃。

引用计数器的查看、添加引用和降低引用:

Person *person1=[ [Person alloc] init];//创建一个Person对象,retainCount为1

NSLog(@”%ld”,[person1retainCount]);//1

Person *person2= [person1 retain];//person2指针和person1指向同一个对象,计数器+1

NSLog(@”%ld”,[person2retainCount]);//2

[person2release];//1

[person1release];//0。自己主动调用dealloc销毁对象

注意:仅仅有通过alloc、new、copy方式创建的对象才有全部权;其它方式创建的指针想拥有全部权,须要发送retain消息获得全部权。

那就意味着,若指向对象的指针有非常多个,而拥有全部权的指针恰好等于引用计数器中的数字;仅仅有拥有全部权的指针,才有资格使引用计数器做减1操作。

4、相关概念

野指针错误:訪问了一块坏的内存(已经被回收的,不可用的内存)。

僵尸对象:所占内存已经被回收的对象。僵尸对象不能再被使用(打开僵尸对象检測)。

空指针:没有指向不论什么东西的指针(存储的东西是0,null,nil)。给空指针发送消息不会报错。

四、内存管理法则

The basic ruleto apple is everything thatincreases the reference counter withalloc,[mutable]copy[WithZone:] or retainis in charge of the corresponding[auto]release.

假设一个对象使用了alloc、[mutable]copy、retain,那么你必须使用对应的release或autonrelease。

(1)仅仅要还有人在使用某个对象。那么这个对象就不会被回收;仅仅要你想使用这个对象,那么就应该让这个对象的引用计数器+1;当你不想使用这个对象时,应该让对象的引用计数器-1;

(2)谁创建。谁负责release。假设你通过alloc,new,copy来创建了一个对象,那么你就必须调用release或者autorelease方法;不是你创建的就不用你去负责。

(3)谁retain,谁负责release。

仅仅要你调用了retain,不管这个对象时怎样生成的,你都要调用release。

五、自己主动释放池的使用

@autoreleasepool{

Person *person1=[[ [Person alloc] init]autorelease];

……

}

六、Autorelease

1、基本使用方法

(1)autorelease会将对象放到一个自己主动释放池中;

(2)当自己主动释放池被销毁时。会对池子里的全部对象发送一条release。最后销毁自身。

注意:给全部对象发送一条release消息,并非销毁对象。

自己主动释放池能够嵌套使用。自己主动释放池遵从栈式管理,在iOS程序执行过程中,会创建无数个池子,这些池子都是以栈结构(先进后出)存在的。当一个对象调用autorelease时。会将这个对象放到位于栈顶的释放池中。

每当向对象发送一条autorelease消息时,就是将其放到近期的一个自己主动释放池。增加到autorelease中的对象。不须要手动发送release。

2、自己主动释放池的优劣

使用自己主动释放池的优点是:

(1)不须要再关心对象释放的时间;

(2)不须要再关心什么时候调用release。

注意,创建对象时发送了autorelease之后,就不能再对对象发送release消息。

自己主动释放池的劣势是:自己主动释放池具有延迟性,仅仅有到达结束边界时,才会给当中的全部对象发送release消息。占用内存较大的对象,不要随便使用autorelease,应该使用release来精确控制。

3、自己主动释放池的创建方式

(1)ios 5.0曾经的创建方式

NSAutoreleasePool*pool=[[NSAutoreleasePool alloc] init];

`````````````````

[pool release];//[pool drain];用于mac

(2)Ios5.0以后

@autoreleasepool

{//開始代表创建自己主动释放池

·······

}//结束代表销毁自己主动释放池

4、Autorelease注意

(1)系统自带的方法中。假设不包括alloc new copy等,则这些方法返回的对象都是autorelease的,如[NSDate  date];

(2)开发中常常会写一些类方法来高速创建一个autorelease对象,创建对象时不要直接使用类名,而是使用self。

七、常见的属性keyword

1、常见属性keyword

OC中属性声明例如以下:

@property (nonatomic, assign)
int B;

@property (nonatomic, retain)
id classObj;

能够看到keyword@property后的括号出现了四个特征性keyword:nonatomic , assign , retain , settet,
这些keyword直接告诉编译器后面的变量用何种方式来存取。

常见的属性keyword例如以下:

属性keyword

使用范围

含义

是否默认值

备注

assign

赋值方式

不复制不保留,直接赋值

YES

基本数据类型和本类不直接拥有的对象

retain

赋值方式

将新值保留一份,覆盖原值

NO

大部分对象可用

copy

赋值方式

将新值复制一份赋覆盖原值

NO

字符串选择性使用

readwrite

读写权限

生成getter和setter两个方法

YES

变量可读取可改动

readonly

读写权限

仅仅生成getter方法

NO

变量仅仅读不可改动

atomic

原子性

原子操作

YES

能够保留在多线程环境下,能安全的存取值

nonatomic

原子性

非原子操作

NO

不生成多线程同步内容

getter

存取方法

自己定义取方法

NO

 

setter

存取方法

自己定义赋值方法

NO

 

关于nonatomic,假设我们能确定不须要多线程訪问时,强烈推荐使用这个keyword,由于atomic对于性能的损失相对较大。

假设是类的delegate,推荐使用assignkeyword。原因是避免了retain的死循环造成的对象无法真正的释放。

2、ARC新增的属性keyword

ARC新增两个属性keyword:strong
和weak。strong的含义和retain同样。weak和assign同样,修饰完的属性变量使用方法也是全然没有改变,只是strong和weak仅仅能修饰对象。

八、举例说明属性与内存管理

比方有一个引擎类Engine,有一个汽车类Car,Car里面有一个Engine的实例变量,一个setter和getter方法。代码例如以下:

#import"Car.h"

@implementationCar

//setter

-(void)setEngine:(Engine*)engine

{

_engine=engine;

}

//getter

-(Engine*)engine

{

return _engine;

}

//dealloc

-(void)dealloc

{

NSLog(@"Car is dealloc");

[super dealloc];

}

@end

第一步改进:

使用以上定义的类,看问题在哪。在main方法里调用例如以下:

//创建一个引擎对象

Engine*engine1=[[Engine alloc]init];

[engine1 setID:1];

//创建一个汽车对象,并安装引擎

Car* car=[[Car alloc]init];//retainCount=1

[carsetEngine:engine1];

[engin1 release];//错误!

car的引擎将为空,车子被卸掉引擎了!

问题分析:

代码中。有两个引用指向这个Engine对象,engine1和Car中的_engine,但是这个Engine对象的引用计数还为1,由于在set方法中,并没有使用retain。那么无论是哪个引用调用release,那么另外一个引用都会指向一块释放掉的内存。那么肯定会错误发生。

第二步改进:

//setter方法改进

-(void)setEngine:(Engine*)engine

{

_engine=[engine retain];//多了一个引用,retainCount+1

}

在main中调用例如以下:

Engine* engine1=[[Engine alloc]init];

[engine1 setID:1];

Car* car=[[Car alloc]init];//retainCount=1

[car setEngine:engine1];//retainCount=2,由于使用了retain,所以retainCount=2

//如果另一个引擎

Engine* engine2=[[Engine alloc]init];

[engine2 setID:2];

//这个汽车要换一个引擎。自然又要调用settr方法

[carsetEngine:engine2];

问题分析:

代码中,汽车换了一个引擎,那么它的_engine就不再指向engine1的哪个对象的内存了,而是换成了engine2。也就是说指向engine1对象的指针仅仅有一个,而对象本身的retainCount是2。显然内存泄露了。

第三步改进:

-(void)setEngine:(Engine*) engine

{

//在设置之前,先release,那么在设置的时候。就会自己主动将前面的一个引用release掉

[_engine release];

_engine=[engine retain];//多了一个引用,retainCount+1

}

第四步改进:

-(void)setEngine:(Engine*) engine

{

//推断是否反复设置,以防调用时反复赋值

if(_engine!=engine){

//在设置之前,先release,那么在设置的时候,就会自己主动将前面的一个引用release掉

[_engine release];

_engine=[engineretain];//多了一个引用。retainCount+1

}

}

第五步改进:

如今setter方法基本没有问题了,那么在当我们要释放掉一个car对象的时候。必须也要释放它里面的_engine的引用,所以,要重写car的dealloc方法:

-(void)dealloc

{

[_engine release]; //在释放car的时候,释放掉它对engine的引用

[super dealloc];

}

以上操作看似没问题,但误操作时会向僵尸对象发送消息引起程序崩溃。所以还不是最好的释放的方法,以下的方法更好:

-(void)dealloc

{    //在释放car的时候。对setEngine设置为nil,它不仅会release掉。而且指向nil,即使误操作调用也不会出错

[_engine setEngine:nil];

[super dealloc];

}

所以。综上所述。在setter方法中的终于写法是:

<spanstyle="color:#CC66CC;">-(void)setEngine:(Engine*) engine

{

if(_engine!=engine){

[_engine release];

_engine=[engine retain];

}

}

然后在dealloc方法中写法是:

-(void)dealloc

{

[_engine setEngine:nil];

[super dealloc];

}

八、property中的setter语法keyword

在property属性中有3个keyword定义关于展开setter方法中的语法。assgin(缺省),retain。copy。

当然这三个keyword是相互排斥的。

1、assgin展开stter的写法

-(void)setEngine:(Engine*) engine

{

_engine=engine;

}

2、retain展开的写法

-(void)setEngine:(Engine*) engine

{

if(_engine!=engine){

[_enginerelease];

_engine=[engineretain];

}

}

能够看到,使用retain和我们上面举得样例全然同样,所以我们能够使用property和它的retain取代之前的写法。

3、copy展开的写法

-(void)setEngine:(Engine*) engine

{

if(_engine!=engine){

[_engine release];

_engine=[enginecopy];

}

}

对于copy属性有一点要主要,被定义有copy属性的对象必需要符合NSCopying协议,而且你还必须实现了-(id)copyWithZone:(NSZone*)zone该方法。

九、ARC

1、ARC的推断准则

仅仅要没有强指针指向对象。对象就会被释放。

2、指针分类

(1)强指针:默认的情况下,全部的指针都是强指针,keywordstrong;

(2)弱指针:_ _weakkeyword修饰的指针。

声明一个弱指针例如以下:

_ _weak Person*p;

ARC中,仅仅要弱指针指向的对象不在了。就直接把弱指针做清空操作。

_ _weak Person*p=[[Person alloc]  init];//不合理,对象一创建出来就被释放掉,对象释放掉后,ARC把指针自己主动清零。

ARC中在property处不再使用retain,而是使用strong。在dealloc中不须要再[superdealloc]。

@property(nonatomic,strong)Dog *dog;//
意味着生成的成员变量_dog是一个强指针。相当于曾经的retain。

假设换成是弱指针,则换成weak。不须要加_ _。

3、ARC的特点

(1)不同意调用release。retain。retainCount。

(2)同意重写dealloc,可是不同意调用[superdealloc]。重写时全局指针都置nil。

(3)@property的參数

strong:相当于原来的retain(适用于OC对象类型)。成员变量是强指针。

weak:相当于原来的assign(适用于OC对象类型),成员变量是弱指针。

iOS开发中的内存管理的更多相关文章

  1. Unity游戏开发中的内存管理_资料

    内存是手游的硬伤——Unity游戏Mono内存管理及泄漏http://wetest.qq.com/lab/view/135.html 深入浅出再谈Unity内存泄漏http://wetest.qq.c ...

  2. Cocos2d-x开发中C++内存管理

    由于开始并没有介绍C++语言,C++的内存管理当然也没进行任何的说明,为了掌握Cocos2d-x中的内存管理机制,是有必要先了解一些C++内存管理的知识.C++内存管理非常复杂,如果完全地系统地介绍可 ...

  3. Cocos2d-x开发中Ref内存管理

    Ref类是Cocos2d-x根类,Cocos2d-x中的很多类都派生自它,例如,我们熟悉的节点类Node也派生自Ref.我们介绍Ref内存管理.内存引用计数Ref类设计来源于Cocos2d-iphon ...

  4. ios 开发中使用SVN管理代码

    今天新公司需要使用SVN管理代码,就在网上查看相关的资料,现在把相关用法记录下来: 1.使用的是这个软件Cornerston 网上有很多相应的下载链接,可以去查看 2.下载安装之后,首先需要添加仓库r ...

  5. iOS开发中的内存分配(堆和栈)

    进程的内存分区 所有进程(执行的程序)都必须占用一定数量的内存,它或是用来存放从磁盘载入的程序代码,或是存放取自用户输入的数据等等.不过进程对这些内存的管理方式因内存用途不一而不尽相同,有些内存是事先 ...

  6. CocoaPoda在iOS开发中的使用

    CocoaPoda在iOS开发中的使用 CocoaPods 简介 CocoaPods是iOS开发中不可避免的依赖管理第三方的工具,能简化一些第三方库文件需要添加编译参数及依赖库的繁复工作 CocoaP ...

  7. [转载]对iOS开发中内存管理的一点总结与理解

    对iOS开发中内存管理的一点总结与理解   做iOS开发也已经有两年的时间,觉得有必要沉下心去整理一些东西了,特别是一些基础的东西,虽然现在有ARC这种东西,但是我一直也没有去用过,个人觉得对内存操作 ...

  8. iOS 非ARC基本内存管理系列 -手把手教你ARC——iOS/Mac开发ARC入门和使用(转)

    手把手教你ARC——iOS/Mac开发ARC入门和使用 Revolution of Objective-c 本文部分实例取自iOS 5 Toturail一书中关于ARC的教程和公开内容,仅用于技术交流 ...

  9. iOS 下ARC的内存管理机制

    本文来源于我个人的ARC学习笔记,旨在通过简明扼要的方式总结出iOS开发中ARC(Automatic Reference Counting,自动引用计数)内存管理技术的要点,所以不会涉及全部细节.这篇 ...

随机推荐

  1. PowerShell中的一个switch的例子

    在这个例子中, 应该注意 Switch语句里对数字范围条件的使用 break的使用 字符串的拼接 数组的声明   ) foreach ($element in $array) { switch($el ...

  2. mysql 跟踪sql执行方法

    摘 自: http://bbs.jee-soft.cn:8086/showtopic-166.aspx 日志是调试程序非常有用的工具. 1  配置my.ini文件(在安装目录,linux下文件名为my ...

  3. PLSQL Developer连接远程Oracle方法(非安装client)

    远程连接Oracle比較麻烦,通常须要安装oracle的客户端才干实现. 通过instantclient能够比較简单的连接远程的Oracle. 1.新建文件夹D:\Oracle_Cleint用于存放相 ...

  4. java 二维码编码解码

    做一个小项目的时候写了个二维码编码和解码的小工具,感觉可能用得到,有兴趣的朋友可以看下 再次之前,徐需要用到google的zxing相关的jar包,还有javax相关包 以上为可能用到的jar pac ...

  5. centos查看哪些包提供指定头文件

    [问题]:项目迁移时,原来在suse上正常的代码在centos上报错: g++ -g -Wall -fPIC -I../include -I./ -I../src -I/share/comm_ext ...

  6. iOS开发之使用UICollectionView实现美团App的分类功能【偶现大众点评App的一个小bug】

    郝萌主倾心贡献,尊重作者的劳动成果,请勿转载. 假设文章对您有所帮助,欢迎给作者捐赠,支持郝萌主,捐赠数额任意,重在心意^_^ 我要捐赠: 点击捐赠 Cocos2d-X源代码下载:点我传送 游戏官方下 ...

  7. Android-自己定义PopupWindow

    Android-自己定义PopupWindow 2014年5月12日 PopupWindow在应用中应该是随处可见的,非经常常使用到,比方在旧版本号的微信其中就用到下拉的PopupWindow.那是自 ...

  8. [ES6] 06. Arrow Function =>

    ES6 arrow function is somehow like CoffeeScirpt. CoffeeScript: //function call coffee = -> coffee ...

  9. Nginx + FastCGI 程序(C/C++)搭建高性能web service的demo

    http://blog.csdn.net/chdhust/article/details/42645313 Nginx + FastCGI 程序(C/C++)搭建高性能web service的Demo ...

  10. Expression-Based Access Control

    Expression-Based Access Control Spring Security 3.0 introduced the ability to use Spring EL expressi ...