想驾驭一门语言,首先要掌握它的内存管理特性。iOS开发经历了MRC到ARC的过程,下面就记录一下本人对iOS内存管理方面的一些理解。

说到iOS开发,肯定离不开objective-c语言(以下简称OC)。OC的内存管理机制叫做引用计数,就是一块内存地址可以同时被多个对象引用,每引用一次,引用计数都会递增1,当对象每解除一次引用,引用计数就会递减1,直到引用计数为0时,系统才会讲这块内存地址回收释放掉,这与C/C++语言有些不同,但是它们都遵守同一个内存管理法则:谁申请,谁释放。

在早些时候,iOS开发只能使用MRC,通过retain、release来递增引用计数和递减引用计数。但是OC语言的设计者发现,光有这些可能会违背内存管理法则,比如下面代码所示:

- (People *)blackPeople {
People *p = [People new];return p;
}

这段代码有2个问题:

1. 方法在堆空间上创建了一块内存地址,并用一个局部指针变量p指向它,然后将指针p返回给调用者使用(函数返回都是值拷贝)。在这之前不能调用[p release];操作,因为这会使p指针成为野指针。所以最终就要求使用者必须负责释放内存,然而调用者并不应该有这个义务。说好的谁申请,谁释放呢?

2. 在这里要说明一下,在iOS开发中是很注重方法命名的,很多人不是太理解这个说法,笔者在此提醒大家,不注重方法命名,内存管理就会变的很糟糕,尤其是在使用了ARC时,更是应该注意。下面会详细说明。就以上代码来看,如果就想让调用者负责管理内存,我们这样返回没有问题,但是方法的名字不合适,从blackPeople中,我们看不出来任何信息是要求调用者来负责管理内存的,因此调用者肯定不会去负责内存的管理,从而导致内存泄漏。

解决以上2个问题:

1. OC语言的设计者加入了一个autorelease的概念,从名字就可以看出来,是让对象自动释放。这就很好的解决了问题1,如下面正确代码:

- (People *)blackPeople {
People *p = [People new];
return [p autorelease];
}

这样,在堆上分配的这块内存,就会在某个时间点自动递减引用计数,而不需要调用者去管理。

2. 我们应该更改方法名字为newBlackPeople或者allocBlackPeople还有copyBlackPeople。大家可能发现,方法名称中有new、alloc、copy这样的字眼,没错,通过这些词语,任何人都很清楚,此方法返回的对象是需要自己管理内存的。

以上就是MRC机制使用过程中会遇到的内存管理相关的操作语句,至于autorelease到底会在哪个时间点去自动递减引用计数,答案是在下一个runloop开始之前,读者可以去查看runloop的相关知识。

使用MRC难免会产生内存管理方面的问题,因此苹果公司在Xcode中整合了一款名为Clang的静态分析器,帮助开发者发现内存错误,比如内存泄漏或者过早释放。既然Clang可以出色的完成它的工作,那为何不能自动的帮助开发人员插入retain和release来管理内存呢?显然是可行的,因此就有了ARC机制。

如今,iOS开发人员基本都在使用ARC,笔者总结了2点:ARC能够通过方法名称帮助开发人员管理内存;ARC比MRC更效率。下面开始介绍:

1. 刚才在上面提到过方法命名的重要性,这里详细说一下。如果方法名以alloc、new、copy、mutableCopy开头,那么其返回的对象归调用者负责内存管理。正因为ARC以这个规则工作,所以我们必须注重方法命名。看下面代码:

+ (People *)newPeople {
People *p = [[People alloc] init];
return p;
// 方法名中以new开头,所以ARC知道返回的对象该由调用者管理其内存,因此此处不插入
// 任何代码
} + (People *)blackPeople {
People *p = [[People alloc] init];
return p;
// 方法名中没有以上面4种词语开头,所以ARC知道放回的对象该由方法内部管理其内存,
// 因此此处会插入autorelease,最终代码为:return [p autorelease];
} - (void)doSomething {
People *p1 = [People newPeople];
People *p2 = [People somePeople];
// 通过上面的说明,这里大家应该知道,ARC会在方法的最后插入[p1 release];
}

2. ARC在调用retain、release等操作时并不通过普通的OC消息派发机制,而是直接调用底层的C语言版本。而且保留及释放操作需要频繁执行,直接调用底层函数能够节省很多CPU周期,性能更好。比如ARC调用与retain等价的底层函数objc_retain。而且ARC会发现在同一个对象上执行了多次retain和release操作,那么它会成对的移除这些语句。

在ARC机制下,每个变量都是指向对象的强引用(strong),会递增引用计数。看下面代码:

_people = [People blackPeople];
// 可以知道,blackPeople返回对象时已经执行了autorelease操作,但是在ARC机制下,
// 代码其实是下面这样的: People *temp = [People blackPeople];
_people = [temp retain];

可以看出,blackPeople方法中的autorelease和上面代码中的retain是多余的,ARC当然会去优化代码,它会在方法中返回自动释放的对象时,不执行autorelease,而是去调用objc_autoreleaseReturnValue函数。此函数会查看当前方法返回之后即将要执行的那段代码,如果发现那段代码会在返回的对象上执行retain操作,则去设置全局数据结构中的一个标志位,而不执行autorelease操作;同时,调用retain的那边也不直接执行retain操作,而是去执行objc_retainAutoreleasedReturnValue函数。此函数会去检测感概提到的那个标志位,如果已经置位,则不执行retain操作。这样去检测一个标志位,比调用autorelease和retain更快。大概代码如下:

+ (People*)blackPeople {
People *p = [People new];
objc_autoreleaseReturnValue(p);
} // 调用上面方法
People *temp = [People blackPeople];
_people = objc_retainAutoreleasedReturnValue(temp); id objc_autoreleaseReturnValue(id object) {
if (返回将retain对象) {
set_flag(object);
return object; // 不执行autorelease
} else {
return [object autorelease];
}
} id objc_retainAutoreleasedReturnValue(id object) {
if (get_flag(object)) {
clear_flag(object);
return object; // 不执行retain
} else {
return [object retain];
}
}

补充:当我们进行MRC与ARC混编的时候,尤其要注意编码规范,也就是上面一直强调的方法命名规则,看下面代码:

// 假如在MRC下编写了下面这段代码,意思是想让调用者去管理返回对象的内存,
// 然而方法命名确是blackPeople - (People *)blackPeople {
People *p = [People new];
return p;
} // 将如在ARC中调用了上面的方法
- (void)testFun
{
People *people = [[People alloc] init];
people = [people blackPeople];
people = nil;
// 首先在ARC下,第一行代码会申请一块内存,第二行代码调用了blackPeople方法,
// 也会申请一块内存。在ARC看来,它需要将申请的第一块内存释放,
// 然后再让people变量指向申请的第二块内存,这符合我们的意愿。
// 但是要注意第三行代码,尽管我们将people变量置为nil,但ARC并不会去按照我们
// 的意思去释放内存,因为ARC是遵守规则的,它根据blackPeople方法的命名,知道
// 对象的内存由申请者管理,就不需要自己去管理了,从而导致了内存泄漏。
  // 解决的办法就是我们应该遵守规范,这样返回对象:return [p autorelease];
}

还有就是不小心可能会重复释放同一块内存,造成程序崩溃,这里就不上代码了。

以上就是笔者的一些总结,希望能帮助到大家。

iOS内存管理 ARC与MRC的更多相关文章

  1. 【Bugly干货分享】iOS内存管理:从MRC到ARC实践

    Bugly 技术干货系列内容主要涉及移动开发方向,是由Bugly邀请腾讯内部各位技术大咖,通过日常工作经验的总结以及感悟撰写而成,内容均属原创,转载请标明出处. 对于iOS程序员来说,内存管理是入门的 ...

  2. iOS 内存管理:从 MRC 到 ARC 实践

    对于 iOS 程序员来说,内存管理是入门的必修课.引用计数.自动释放等概念,都是与 C 语言完全不同的. iOS 内存管理的核心是引用计数. 接触 MRC 时遇到最头疼的问题就是:为什么那么多 rel ...

  3. iOS 内存管理arc

    http://www.tekuba.net/program/346/ ios自动释放池(autoreleasepool #import <Foundation/Foundation.h> ...

  4. OC 知识:彻底理解 iOS 内存管理(MRC、ARC)

    1. 什么是内存管理 程序在运行的过程中通常通过以下行为,来增加程序的的内存占用 创建一个OC对象 定义一个变量 调用一个函数或者方法 而一个移动设备的内存是有限的,每个软件所能占用的内存也是有限的 ...

  5. iOS内存管理机制解析之MRC手动引用计数机制

    前言: iOS的内存管理机制ARC和MRC是程序猿參加面试基本必问的问题,也是考察一个iOS基本功是 否扎实的关键,这样深入理解内存管理机制的重要性就不言而喻了. iOS内存管理机制发展史 iOS 5 ...

  6. iOS内存管理

    iOS内存管理的方式是引用计数机制.分为MRC(人式引用计数)和ARC(自动引用计数). 为什么要学习内存管理? 内存管理方式是引用计数机制,通过控制对象的引用计数来实现操作对象的功能.一个对象的生命 ...

  7. IOS内存管理学习笔记

    内存管理作为iOS中非常重要的部分,每一个iOS开发者都应该深入了解iOS内存管理,最近在学习iOS中整理出了一些知识点,先从MRC开始说起. 1.当一个对象在创建之后它的引用计数器为1,当调用这个对 ...

  8. 75.iOS内存管理

    堆区和栈区 1.栈区:由编译器自动分配释放,函数的参数值,局部变量等值 2.堆区:一般由开发人员分配释放,若不释放,则可能会引起内存泄漏 NSString *string = @"abcd& ...

  9. 浅谈iOS内存管理机制

    iOS内存管理机制的原理是引用计数,引用计数简单来说就是统计一块内存的所有权,当这块内存被创建出来的时候,它的引用计数从0增加到1,表示有一个对象或指针持有这块内存,拥有这块内存的所有权,如果这时候有 ...

随机推荐

  1. CSSBox - Java HTML rendering engine

    CSSBox - Java HTML rendering engine CSSBox is an (X)HTML/CSS rendering engine written in pure Java. ...

  2. 【课程分享】ASP.NET MVC5&amp;微信公众平台整合开发实战(响应式布局、JQuery Mobile,Windows Azure、微信核心开发)

    对这个课程有兴趣的,能够联系我QQ2748165793 基础知识储备 ASP.NET MVC 5基础(6讲) 第一讲-初识ASP.NET MVC并搭建整合开发环境 第二讲-深入MVC开发模式 第三讲- ...

  3. 杭州电子科技大学Online Judge 之 “确定比赛名次(ID1285)”解题报告

    杭州电子科技大学Online Judge 之 "确定比赛名次(ID1285)"解题报告 巧若拙(欢迎转载,但请注明出处:http://blog.csdn.net/qiaoruozh ...

  4. POJ 3169 Layout (图论-差分约束)

    Layout Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6574   Accepted: 3177 Descriptio ...

  5. .NET 多语言支持解决方案 (转)

    asp.net 2.0中的App_GlobalResources可以用来解决本地化的问题,程序会根据浏览器的语言首选项自动判断显示出本地化的界面. 首先在App_GlobalResources新建re ...

  6. zoj 1453 Stripies

    /* 根据题意:不难看出,要是整个方程式最小,那么应该大的数先结合,小的数后结合.先排序然后结合(贪心) */ #include<stdio.h> #include<stdlib.h ...

  7. Webform之(简单投票)练习

    创建数据库: CREATE table DiaoYanTiMu ( Ids int primary key ,--题目代号 Title varchar() not null ,--要调查的题目 Sel ...

  8. OC KVC总结

    在iOS开发中,我们一般使用set方法或者点语法来修改对象的属性值,比如说 stu.age = 9 与 [stu setAge:9]. KVC(key value coding)键值编码,这是一种间接 ...

  9. Mac下搭建SVN服务器

    1.检查机器上是否安装svnserve zhangdeqiangdeiMac:Downloads hengjiang$ svnserve --version svnserve, version (r1 ...

  10. Windows系统中使用WMI获取远程服务器的信息

    使用WMI获取远程服务器的状态 我做的项目里边主要包含两个内容: (1)对发布在服务器上的服务(IIS服务.WCF服务)是否可以正常访问: (2)获取服务器上的部分指标:如CPU.内存.磁盘空间信息等 ...