iPhoneMac Objective-C内存管理教程和原理剖析
- 格式:pdf
- 大小:224.75 KB
- 文档页数:9
Objective-C提供了三种内存管理方式:manual retain-release(MRR,手动管理),automatic reference counting(ARC,自动引用计数),garbage collection(垃圾回收)。
iOS不支持垃圾回收;ARC作为苹果新提供的技术,苹果推荐开发者使用ARC技术来管理内存;这篇笔记主要讲的是手动管理。
内存管理的目的是:1.不要释放或者覆盖还在使用的内存,这会引起程序崩溃;2.释放不再使用的内存,防止内存泄露。
iOS程序的内存资源是宝贵的。
MRR手动管理内存也是基于引用计数的,只是需要开发者发消息给某块内存(或者说是对象)来改变这块内存的引用计数以实现内存管理(ARC技术则是编译器代替开发者完成相应的工作)。
一块内存如果计数是零,也就是没有使用者(owner),那么objective-C的运行环境会自动回收这块内存。
objective-C的内存管理遵守下面这个简单的策略:注:文档中把引用计数加1的操作称为“拥有”(own,或者take ownership of)某块对象/内存;把引用计数减1的操作称为放弃(relinquish)这块对象/内存。
拥有对象时,你可以放心地读写或者返回对象;当对象被所有人放弃时,objective-C的运行环境会回收这个对象。
1.你拥有你创建的对象也就是说创建的对象(使用alloc,new,copy或者mutalbeCopy等方法)的初始引用计数是1。
2.给对象发送retain消息后,你拥有了这个对象3.当你不需要使用该对象时,发送release或者autorelease消息放弃这个对象4.不要对你不拥有的对象发送“放弃”的消息注:简单的赋值不会拥有某个对象。
比如:...NSString *name = ;...上面这个赋值操作不会拥有这个对象(这仅仅是个指针赋值操作);这和C++语言里的某些基于引用计数的类的行为是有区别的。
Objective-C 入门教程分类编程技术Objective-C是一种简单的计算机语言,设计为可以支持真正的面向对象编程。
Objective-C 通过提供类定义,方法以及属性的语法,还有其他可以提高类的动态扩展能力的结构等,扩展了标准的ANSI C语言。
类的语法和设计主要是基于Smalltalk,最早的面向对象编程语言之一。
如果你以前使用过其他面向对象编程语言,那么下面的信息可以帮助你学习Objective-C 的基本语法。
许多传统的面向对象概念,例如封装,继承以及多态,在Objective-C中都有所体现。
这里有一些重要的不同,但是这些不同在这文章会表现出来,而且如果你需要还有更多详细的信息存在。
如果你从来没有使用任何编程语言编过程序,那么你至少需要在开始之前,对相关概念进行一些基础的了解。
对象的使用和对象对象架构是iPhone程序设计的基础,理解他们如何交互对创建你的程序非常重要。
想了解面向对象概念的,请参看使用Objective-C进行面向对象编程。
此外,参看Cocoa基础指南可以获得Cocoa中的面向对象设计模式的信息。
Objective-C:C的超集Objective-C是ANSI版本C编程语言的超集,支持C的基本语法。
在C代码中,你定义头文件和源代码文件,从代码实现细节分离公共声明。
Objective-C头文件使用的文件名列在表1中。
表1 Objective-C代码的文件扩展名扩展名内容类型.h 头文件。
头文件包含类,类型,函数和常数的声明。
.m 源代码文件。
这是典型的源代码文件扩展名,可以包含Objective-C和C代码。
.mm 源代码文件。
带有这种扩展名的源代码文件,除了可以包含Objective-C和C代码以外还可以包含C++代码。
仅在你的Objective-C代码中确实需要使用C++类或者特性的时候才用这种扩展名。
当你需要在源代码中包含头文件的时候,你可以使用标准的#include编译选项,但是Objective-C提供了更好的方法。
objective-c基础教程——学习小结提纲:简介与C语言相比要注意的地方objective-c高级特性开发工具介绍(cocoa 工具包的功能,框架,源文件组织;XCode使用介绍)简介:1. objective-c是C语言的一个扩展集,主要由APPLE公司维护,是MAC系统下的主要开发语言。
个人认为,对于用惯了常用的C,JAVA等语言的人来说,objective-c是一中很另类,非主流的语言。
2. 开发Mac的UI 程序来说,使用的是Cocoa 这个框架,cocoa的组成部分有:foundation和application kit框架。
【foundation框架处理用户界面之下的特性,如数据结构和通信机制;application kit框架包含cocoa的高级特性:用户界面元素,打印,颜色,声音管理,applescript等】3. 我通过这本书的学习:基本掌握了Objective C的语法,基本能看懂别人写的代码,自己也能编写代码;熟悉了开发环境XCode的使用;(包括建立项目,调试,运行,代码管理等)与C语言相比要注意的地方:1. 文件介绍:Objective-C 也使用头文件(header files),后缀为 .h, 但使用 .m(即message, 其他面向对象编程语言也叫method),作为源文件的后缀。
在objective-c中使用#import<>,而不使用#include<>,#import可以保证头文件只被包含一次。
2. 与C一致的地方:数据类型,表达式,各种运算符循环:for, while, do while, break, continue分支:if, else, switch3. NSlog()函数:与printf()类似,想控制台输出信息。
但它增加了一些特性,如时间戳等。
【cocoa对起所有的函数,常量和类型名称都添加了NS前缀。
】4. 双引号的前面的@表示这双引号中的字符串应该作为cocoa的NSString元素来处理。
Objective-C 2.0之前需要了解的:关于Obj-C内存管理的规则/index.php/archives/cocoachina_110.htmlObjective-C 2.0增加了一些新的东西,包括属性和垃圾回收。
那么,我们在学习Objective-C 2.0之前,最好应该先了解,从前是什么样的,为什么Objective-C 2.0要增加这些支持。
这一切都跟Cocoa内存的管理规则有关系,我们知道,Objective-C中所有变量都定义为指针。
指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址,如果使用不当,就会出错或者造成内存的泄露。
要了解这些,就需要看看其内存管理的规则到底是什么样的。
这篇文章也应该做为苹果开发工具中提供的性能调试工具Instruments使用前必读知识进行阅读。
Cocoa China将在稍后提供Instruments工具的使用方法,以及Objective-C 2.0的详细介绍。
要知道,如果你使用Objective-C 2.0,那么本文描述的大部分工作你都不需要自己去处理了。
但是这并不意味着你可以不了解它,相反,只有你对内存管理规则更加了解,你才能更好地使用Objective-C 2.0带来的便利。
本文原文作者是Mmalcolm Crawford,原文地址这篇文章翻译起来比较晦涩,希望您能看得懂。
当Cocoa新手在进行内存管理时,他们看上去总是把事情变得更为复杂。
遵循几个简单的规则就可以把生活变得更简单。
而不遵循这些规则,他们几乎一定会造成诸如内存泄露或者将消息发送给释放掉的对象而出现的的运行错误。
Cocoa不使用垃圾回收(当然,Objective-C 2.0之后开始就使用了),你必须通过计算reference的数量进行自己的内存管理,使用-retain, -release和-autorelease。
方法描述-retain将一个对象的reference数量增加1。
前言初学objectice-C的朋友都有一个困惑,总觉得对objective-C的内存管理机制琢磨不透,程序经常内存泄漏或莫名其妙的崩溃。
我在这里总结了自己对objective-C内存管理机制的研究成果和经验,写了这么一个由浅入深的教程。
希望对大家有所帮助,也欢迎大家一起探讨。
此文涉及的内存管理是针对于继承于NSObject的Class。
一、基本原理Objective-C的内存管理机制与.Net/Java那种全自动的垃圾回收机制是不同的,它本质上还是C语言中的手动管理方式,只不过稍微加了一些自动方法。
1 Objective-C的对象生成于堆之上,生成之后,需要一个指针来指向它。
ClassA *obj1 = [[ClassA alloc] init];2 Objective-C的对象在使用完成之后不会自动销毁,需要执行dealloc来释放空间(销毁),否则内存泄露。
[obj1 dealloc];这带来了一个问题。
下面代码中obj2是否需要调用dealloc?ClassA *obj1 = [[ClassA alloc] init];ClassA *obj2 = obj1;[obj1 hello]; //输出hello[obj1 dealloc];[obj2 hello]; //能够执行这一行和下一行吗?[obj2 dealloc];不能,因为obj1和obj2只是指针,它们指向同一个对象,[obj1 dealloc]已经销毁这个对象了,不能再调用[obj2 hello]和[obj2 dealloc]。
obj2实际上是个无效指针。
如何避免无效指针?请看下一条。
3 Objective-C采用了引用计数(ref count或者retain count)。
对象的内部保存一个数字,表示被引用的次数。
例如,某个对象被两个指针所指向(引用)那么它的retain count为2。
需要销毁对象的时候,不直接调用dealloc,而是调用release。
学习Objective-C入门教程1,前言相信iPhone不久就要在国内发布了,和我们在国内可以通过正规渠道买得到的iPodTouch一样,iPhone也是一个激动人心的产品。
iPhone发布的同时,基于iPhone的程序也像雨后春笋一样在iTunes里面冒出来。
你将来也许会考虑买一个iPhone,体验一下苹果的富有创意的种种应用;你也许会考虑向iTunes的社区的全世界的人们展示一下你非凡的创意,当然也可以通过你的创意得到一些意想不到的收益。
OK,你也许迫不及待的准备开发了。
但是先等一下,让我们回忆一下最初的电影是怎么拍摄的。
这个很重要,因为和iPhone的开发比较类似。
在最初因为器材比较原始,所以拍摄电影需要很高的技术,那个时候的电影的导演基本上是可以熟练操作摄影器材的人。
随着器材的完善,使用也简单起来。
于是器材的使用不是决定一个电影的质量的唯一的因素,取而代之的是故事或者说电影的创意。
iPhone的开发也是这样。
当然从入门到掌握的过程来说任何事情都是开始比较难,随着掌握的程度的加深,你将会觉得开发iPhone应用程序是一件简单而且轻松的事情,到了那个时候,你的主要的制胜武器就不是开发技术,而是你的创意了。
对于你来说,我在这里写的东西都是有关“摄影器材”也就是介绍如何使用iPhone的平台来开发应用程序。
iPhone的开发语言是Objective-C。
Objective-C是进行iPhone开发的主要语言,掌握了Objective-C的基本语法以及数据结构之后,你需要熟悉一下iPhone的SDK。
笔者很难做到在一篇文章里面把所有的东西都介绍清楚,所以笔者打算分成两个主题,一个是Objective-C,一个是iPhone开发。
本系列将侧重于Objective-C。
当然,任何一种开发语言都无法脱离于运行环境,Objective-C也不例外。
所以在本系列当中也会穿插的介绍一些SDK里面的一些特性,主要是数据结构方面,比如说NSString,NSArray等等。
简单讲解Objective-C的基本特性及其内存管理方式这篇文章主要介绍了简单讲解Objective-C的基本特性及其内存管理方式,虽然Swift语言出现后iOS和Mac OS应用开发方面Objective-C正在成为过去时,但现有诸多项目仍然在使用,需要的朋友可以参考下一、OC简介Oc语言在c语言的基础上,增加了一层最小的面向对象语法,完全兼容C语言,在OC代码中,可以混用c,甚至是c++代码。
可以使用OC开发mac osx平台和ios平台的应用程序。
拓展名:c语言-.c OC语言.-m 兼容C++.-mm注:其实c语言和oc甚至任何一门语言都只是我们为了实现一些功能,达到一些效果而采用的工具,抛开语法的差别外,我想最重要的应该是在解决问题的时候考虑的角度和方法不一样而已,然而这也构成了学习一门语言的重要性。
二、语法预览(1)关键字基本上所有的关键字都是以@开头的(为了与c语言的关键字区分开来),如@interface @implemen tation @public等,少部分没有以@开头,如id,_cmd等(2)字符串以@开头C语言字符串:“hello”OC语言字符串:@“hello”(3)其他语法基本类型:5种,增加了布尔类型Nil相当于是null,也就是0。
屏幕输出:NSLog(@“hello”);//自动换行NSLog(@“age is %d”,2);三、OC程序开发过程#import预处理指令有两个作用:(1)与#include一样,拷贝文件内容(2)可以自动防止文件的内容被重复拷贝程序编译连接过程:源文件(.m)---(编译)---->目标文件(.0)-----(链接)---->可执行文件(.out)Foundation框架。
如果要使用框架中的所有头文件那么应该怎么办?包含框架的主头文件。
主头文件是一个框架中最主要的头文件,每个框架的主头文件名和框架名一致。
如#import<foundation/foundation.h>运行过程如下:(1)编写OC源文件 .m .c(2)编译文件 cc -c xx.m xxx.c(3)链接 cc xx.o xxx.o -framework Foundation(4)运行 ./a.out四、类型补充复制代码代码如下:Int main(){BOOL b=YES;BOOL b1=NO;BOOL b2=1;// YESBOOL b3=2;// NONSLog(@“%i”,b);}BOOL类型与其他类型的用法一致,BOOL类型的本质是char类型的,定义如下:复制代码代码如下:Typedef signed char BOOL宏定义:复制代码代码如下:#define YES (BOOL)1#define NO (BOOL)0布尔类型的输出一般当做整数来用。
教程详细:技术:Objective-C 难度:初学者完成时间:20-30分钟欢迎来到学习Objective-C系列教程的第五部分,今天我们要看看内存管理,这是特意为新手准备的一个Objective-C的章节哟。
大部分脚本语言(如PHP)则采取内存自动管理,但Objective-C需要我们慎用内存,需要我们手动创建和释放对象。
这是挺好的做法,这让我们控制多少内存被应用程序使用,这样,你就不会遇到系统内存的泄漏了。
更重要的是,移动系统,例如iPhone的内存比台式机器更有限。
两种方式在Objective-C中有两种内存管理方式,第一种是引用计数,第二种是垃圾回收。
你可以认为是手动和自动两种,因为计数引用是用程序代码实现的,垃圾回收是系统自动管理内存的。
有一点要注意的是iPhone没有垃圾回收功能,这就是为什么我们不深究其工作的原因。
如果你的程序是运行Mac上,你可以在苹果的文档上获释垃圾回收的工作原理。
引用计数嗯~,我们该如何管理内存呢?首先,什么时候在我们的代码里使用到内存?当你创建一个类的实例时,内存就被申请了并且我们能使用它。
现在,一个小小的对象也许还不能体现大大的关注,但当你的应用程序规模大起来时,它马上要引起注意的了。
让我们先看看一个例子吧,我们有一些绘画的应用程序,每个图形的形状是单独的对象。
如果用户画了100个形状,这样在内存里就有一百个对象了。
现在,我们的用户重新开始并清除屏幕后,接着画另外100个对象。
如果我们没有管理好我们的内存,我们将有200个对象占着内存而不做任何事情。
我们用引用计数来进行计算。
当我们创建一新对象并申请内存,我们的对象就保留1个计数。
如果我们要求保留这对象,则计数器就变为2。
如果我们释放这个对象,这计数器就变回1。
但当计数器变为0时,系统就会回收这对象,释放内存。
语法有几种可影响我们的内存的方法可供调用。
首先,当我们用一名字包含alloc,新建,复制等方法来创建一对象时,如果你使用对象来保存方法,这也是真实的。
MacOSXIOS内存管理机制简要说明最近身边用苹果的人越来越多,这是一件好事,我很高兴身边的朋友们都能用上世界上最先进的计算机和操作系统,但是大部分朋友都是从Windows过度过来的,从系统使用和原理理解上都有一些Windows的观念,最近很多朋友问我一个问题:“为什么我的系统一开机还没运行什么程序,空余内存就没多少了,我可是4GB内存啊,是不是有什么问题?”针对这一问题,特写此文,让大家理解基于UNIX的Mac OS X是如何管理内存的。
之前转载了一篇文章介绍Unix/Linux的内存管理,但是很多朋友说看不懂,那今天我就通俗的跟大家分享一下,Mac是如何管理内存的。
首先,我们要来了解一下,Mac OS X的内存四种状态,打开你的“应用程序-实用工具-系统监视器”程序,切换到“系统内存”标签,你会看到你的内存有联动、活跃、非活跃和可用空间四种状态:见下图:联动是系统核心占用的,永远不会从系统物理[内存]种清除,活跃表示这些[内存]数据正在使用种,或者刚被使用过,非活跃表示这些[内存]中的数据是有效的,但是最近没有被使用,可用空间表示这些[内存]中的数据是无效的,这些空间可以随时被程序使用。
当可用空间的[内存]低于某个值(这个值是由你的物理[内存]大小决定的),系统则会按照以下顺序使用非活跃的资源。
首先如果非活跃的数据最近被调用了,系统会把它们的状态改变成活跃,并接在原有活跃[内存]逻辑地址的后面, 如果非活跃的[内存]数据最近没有被使用过,但是曾经被更改过而还没有在硬盘的相应虚拟[内存]中做修改,系统会对相应硬盘的虚拟[内存]做修改,并把这部分物理[内存]释放为可用空间供程序使用。
如果非活跃[内存]中得数据被在映射到硬盘后再没有被更改过,则直接释放成可用空间。
最后如果活跃的[内存]一段时间没有被使用,会被暂时改变状态为非活跃。
所以说,如果你的系统里有少量的可用空间内存和大量的非活跃的内存,说明你的[内存]是够用的,系统运行在最佳状态,只要需要,系统就会使用它们,不用担心。
iPhone/Mac Objective-C内存管理教程和原理剖析Vince Yuan (vince.yuan@) 前言初学objectice-C的朋友都有一个困惑,总觉得对objective-C的内存管理机制琢磨不透,程序经常内存泄漏或莫名其妙的崩溃。
我在这里总结了自己对objective-C内存管理机制的研究成果和经验,写了这么一个由浅入深的教程。
希望对大家有所帮助,也欢迎大家一起探讨。
此文涉及的内存管理是针对于继承于NSObject的Class。
一基本原理Objective-C的内存管理机制与.Net/Java那种全自动的垃圾回收机制是不同的,它本质上还是C语言中的手动管理方式,只不过稍微加了一些自动方法。
1、Objective-C的对象生成于堆之上,生成之后,需要一个指针来指向它。
ClassA *obj1 = [[ClassA alloc] init];2、Objective-C的对象在使用完成之后不会自动销毁。
需要执行dealloc来释放空间(销毁),否则内存泄露。
[obj1 dealloc];这带来了一个问题。
下面代码中obj2是否需要调用dealloc?ClassA *obj1 = [[ClassA alloc] init];ClassA *obj2 = obj1;[obj1 hello]; //输出hello[obj1 dealloc];[obj2 hello]; //能够执行这一行和下一行吗?[obj2 dealloc];不能,因为obj1和obj2只是指针,它们指向同一个对象,[obj1 dealloc]已经销毁这个对象了,不能再调用[obj2 hello]和[obj2 dealloc]。
obj2实际上是个无效指针。
如何避免无效指针?请看下一条。
3、Objective-C采用了引用计数(ref count或者retain count)。
对象的内部保存一个数字,表示被引用的次数。
例如,某个对象被两个指针所指向(引用)那么它的retain count为2。
需要销毁对象的时候,不直接调用dealloc,而是调用release。
release会让retain count减1,只有retain count等于0,系统才会调用dealloc真正销毁这个对象。
ClassA *obj1 = [[ClassA alloc] init];//对象生成时,retain count = 1[obj1 release];//release使retain count减1,retain count = 0,dealloc自动被调用,对象被销毁我们回头看看刚刚那个无效指针的问题,把dealloc改成release解决了吗?ClassA *obj1 = [[ClassA alloc] init]; //retain count = 1ClassA *obj2 = obj1; //retain count = 1[obj1 hello]; //输出hello[obj1 release]; //retain count = 0,对象被销毁[obj2 hello];[obj2 release];[obj1 release]之后,obj2依然是个无效指针。
问题依然没有解决。
解决方法见下一条。
4、Objective-C指针赋值时,retain count不会自动增加,需要手动retain。
ClassA *obj1 = [[ClassA alloc] init]; //retain count = 1ClassA *obj2 = obj1; //retain count = 1[obj2 retain]; //retain count = 2[obj1 hello]; //输出hello[obj1 release]; //retain count = 2 – 1 = 1[obj2 hello]; //输出hello[obj2 release]; //retain count = 0,对象被销毁问题解决!注意,如果没有调用[obj2 release],这个对象的retain count始终为1,不会被销毁,内存泄露。
这样的确不会内存泄露,但似乎有点麻烦,有没有简单点的方法?见下一条。
5、Objective-C中引入了autorelease pool(自动释放对象池),在遵守一些规则的情况下,可以自动释放对象。
(autorelease pool依然不是.Net/Java那种全自动的垃圾回收机制)5.1 新生成的对象,只要调用autorelease就行了,无需再调用release!ClassA *obj1 = [[[ClassA alloc] init] autorelease];//retain count = 1 但无需调用release5.2 对于存在指针赋值的情况,代码与前面类似。
ClassA *obj1 = [[[ClassA alloc] init] autorelease]; //retain count = 1 ClassA *obj2 = obj1; //retain count = 1[obj2 retain]; //retain count = 2[obj1 hello]; //输出hello//对于obj1,无需调用(实际上不能调用)release[obj2 hello]; //输出hello[obj2 release]; //retain count = 2-1 = 1细心的读者肯定能发现这个对象没有被销毁,何时销毁呢?谁去销毁它?请看下一条。
6、autorelease pool原理剖析。
6.1 autorelease pool不是天生的,需要手动创立。
只不过在新建一个iphone项目时,xcode 会自动帮你写好。
autorelease pool的真名是NSAutoreleasePool。
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];6.2 NSAutoreleasePool内部包含一个数组(NSMutableArray),用来保存声明为autorelease 的所有对象。
如果一个对象声明为autorelease,系统所做的工作就是把这个对象加入到这个数组中去。
ClassA *obj1 = [[[ClassA alloc] init] autorelease];//retain count = 1,把此对象加入autorelease pool中6.3 NSAutoreleasePool自身在销毁的时候,会遍历一遍这个数组,release数组中的每个成员。
如果此时数组中成员的retain count为1,那么release之后,retain count为0,对象正式被销毁。
如果此时数组中成员的retain count大于1,那么release之后,retain count大于0,此对象依然没有被销毁,内存泄露。
6.4 默认只有一个autorelease pool,通常类似于下面这个例子。
int main (int argc, const char *argv[]){NSAutoreleasePool *pool;pool = [[NSAutoreleasePool alloc] init];// do something[pool release];return (0);} // main所有标记为autorelease的对象都只有在这个pool销毁时才被销毁。
如果你有大量的对象标记为autorelease,这显然不能很好的利用内存,在iphone这种内存受限的程序中是很容易造成内存不足的。
例如:int main (int argc, const char *argv[]){NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];int i, j;for (i = 0; i < 100; i++ ){for (j = 0; j < 100000; j++ )[NSString stringWithFormat:@"1234567890"];//产生的对象是autorelease的。
}[pool release];return (0);} // main运行时通过监控工具可以发现使用的内存在急剧增加,直到pool销毁时才被释放,你需要考虑下一条。
7、Objective-C程序中可以嵌套创建多个autorelease pool。
在需要大量创建局部变量的时候,可以创建内嵌的autorelease pool来及时释放内存。
int main (int argc, const char *argv[]){NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];int i, j;for (i = 0; i < 100; i++ ){NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];for (j = 0; j < 100000; j++ )[NSString stringWithFormat:@"1234567890"];//产生的对象是autorelease的[loopPool release];}[pool release];return (0);} // main运行时通过监控工具可以发现使用占用内存的变化极小。
二口诀与范式1、口诀。
1.1 谁创建,谁释放(类似于“谁污染,谁治理”)。
如果你通过alloc、new或copy来创建一个对象,那么你必须调用release或autorelease。
换句话说,不是你创建的,就不用你去释放。
例如,你在一个函数中alloc生成了一个对象,且这个对象只在这个函数中被使用,那么你必须在这个函数中调用release或autorelease。
如果你在一个class的某个方法中alloc 一个成员对象,且没有调用autorelease,那么你需要在这个类的dealloc方法中调用release;如果调用了autorelease,那么在dealloc方法中什么都不需要做。
1.2 除了alloc、new或copy之外的方法创建的对象都被声明了autorelease。
1.3 谁retain,谁release。
只要你调用了retain,无论这个对象是如何生成的,你都要调用release。
有时候你的代码中明明没有retain,可是系统会在默认实现中加入retain。