本篇博文,将给大家介绍下再Objective-C中如何使用内存管理。一个程序运行的时候,如果不及时的释放没有用的空间内存。那么,程序会越来越臃肿,内存占用量会不断升高。我们在使用的时候,就会感觉很卡,最终使得程序运行奔溃。因此,将无效的内存及时清理释放,是非常有必要的。

  一个对象在最初创建使用,到最后的回收释放,经历的是怎样一个过程呢?
包括:诞生(通过alloc或new方法实现)、生存(接收消息并执行操作)、交友(通过复合以及向方法传递参数)、最终死去(被释放掉)。

一、引用计数

  在对象创建的时候,Cocoa使用了一种叫引用计数的技术:
1)当一个对象被访问的时候,引用计数器的值就加1,可以给对象发送一条retain消息
2)当结束该对象的访问的时候,引用计数器的值就减1,可以给对象发送一条release消息
3)当引用计数器的值为0的时候,表示不再访问该对象,则其占用的系统内存将被回收重用,会自动给对象发送一条dealloc消息,一般都会重写dealloc方法;
4)要获得保留计数器当前的值,可以发送retainCount消息

  下面,介绍下几种方法的声明和实现方法:

首先,新建一个RetainTracker的类,修改类的声明文件和实现方法:

 // RetainTracker.h

 #import <Foundation/Foundation.h>

 @interface RetainTracker : NSObject
-(id) retain;
-(oneway void)release;
-(NSUInteger)retainCount;
@end
 // RetainTracker.m

 #import "RetainTracker.h"

 @implementation RetainTracker
-(id) init
{
if(self == [super init])
{
NSLog(@"init: Retain count of %lu.", [self retainCount]);
}
return (self);
} -(void) dealloc
{
NSLog(@"dealloc called. ByeBye!");
[super dealloc];
} @end

然后在main.m主函数中调用retain,release,retainCount,dealloc等方法:

 #import <Foundation/Foundation.h>
#import "RetainTracker.h" int main(int argc, const char * argv[])
{
RetainTracker *tracker = [RetainTracker new];// count =1 [tracker retain];
NSLog(@"retainCount: %lu", [tracker retainCount]);// count =2 [tracker retain];
NSLog(@"retainCount: %lu", [tracker retainCount]);// count =3 [tracker release];
NSLog(@"retainCount: %lu", [tracker retainCount]);// count =2 [tracker release];
NSLog(@"retainCount: %lu", [tracker retainCount]);// count =1 [tracker retain];
NSLog(@"retainCount: %lu", [tracker retainCount]);// count =2 [tracker release];
NSLog(@"retainCount: %lu", [tracker retainCount]);// count =1 [tracker release];// count =0, dealloc return ();
}

运行结果如下:

二、自动释放

  大家都知道,当对象不再使用的时候,要及时释放。但是在某些情况下,弄清楚什么时候不再使用一个对象并不容易。如果能够自动释放就好了。很幸运,Cocoa中有一个自动释放池(autorelease pool)。细心的朋友可以发现,在ios5以后,每次新建项目,在main函数中都有个@autoreleasepool方法,这就是将执行的代码都加到自动释放池中。

  NSObject类提供了一个叫做autorelease的方法:

 -(id) autorelease;

  该方法预先设定一条会在未来某个时间发送的release消息。当给一个对象发送autorelease消息的时候,实际上是将该对象添加到自动释放池中。当自动释放池被销毁时,会向该池中的所有对象都发送release消息。

  那么,接下来,我们就用添加到自动释放池的方法来修改上面的例子。RetainCount类的内容不改变,只要修改main主函数中的内容:

 /* use auto release pool */
int main(int argc, const char * argv[])
{
NSAutoreleasePool *pool;
pool = [[NSAutoreleasePool alloc] init]; RetainTracker *tracker = [RetainTracker new];// count =1
NSLog(@"after new, tracker: %lu", [tracker retainCount]);// count =1 [tracker retain];
NSLog(@"after retain, tracker: %lu", [tracker retainCount]);// count =2
[tracker autorelease];
NSLog(@"after autorelease, tracker: %lu", [tracker retainCount]);// count =2 [tracker release];
NSLog(@"after release, tracker: %lu", [tracker retainCount]);// count =1
NSLog(@"releasing pool");
[pool release]; // 销毁自动释放池 @autoreleasepool {
RetainTracker *tracker2;
tracker2 = [RetainTracker new]; // count = 1
[tracker2 retain]; //count =2
[tracker2 autorelease]; // count still = 2
[tracker2 release]; //count = 1
NSLog(@"auto releasing pool.");
} return ();
}

  运行结果:

  tracker对象,通过autorelease消息,将该对象添加到自动释放池中。当pool自动释放池发送release消息的时候,pool对象的引用计数器的值为0,则该自动释放池要被销毁,其dealloc方法被调用。使得自动释放池中的对象也都跟随其一起被销毁。

三、内存管理规则

  接下来,就给大家介绍下Cocoa的内存管理的几个规则。

1). 当你使用 new, alloc, copy 方法创建一个对象时,该对象保留计数器的值为1;
     当不使用的时候,要发送一条release或autorelease消息,销毁对象。

 NSMutableArray *array;
array = [[NSMutableArray alloc] init]; //count =1
//use the array
[array release];//dealloc, count =0

2). 当你通过别的方法获得一个对象时,假设该对象的保留计数器的值为1,而已经被设置为自动释放,则不需要执行任何操作来清理该对象。

 NSMutableArray *array;
array = [NSMutableArray arrayWithCapacity: ]; //count =1, autorelease;
//use the array

3). 自动释放池销毁的时间是完全确定的,它在循环阶段是不会被销毁的。如果一个循环要添加到自动释放池中的对象很多的时候,可以考虑循环一部分后先分批释放掉一些,然后再创建新的自动释放池。这样就保证自动释放池的分配和销毁操作代价尽可能的小。

 NSAutoreleasePool *pool;
pool = [ [NSAutoreleasePool alloc] init ];
int i;
for(i=; i<; i++)
{
id object = [someArray objectAtIndex: i];
NSString *desc = [object descrption];
If(i% == )
{
// 每循环一百次就清空一次,然后新建一个自动释放池
[pool release];
pool = [[NSAutoreleaasePool alloc]init];
}
}
[pool release];

4). 自动引用计数(Auto Reference Counting,即:ARC),如果你启用了ARC,只要像平时一样按需分配并使用对象,编译器会帮你插入retain和release,无需你自己手动添加。ARC只能保留Objective-c的指针对象,即:继承NSObject的对象。

5). Ios 5 以上,有了归零弱引用,因为在指向的对象释放之后,这些弱引用就会被设置为零(即:nil),然后对象就会像平常指向nil值的指针一样被处理。使用前要先明确声明,声明方法如下:

 _weak NSString *myString; 或
@property(weak) NSString *myString;

《objective-c基础教程》学习笔记(十)—— 内存管理的更多相关文章

  1. linux kernel学习笔记-5内存管理_转

    void * kmalloc(size_t size, gfp_t gfp_mask); kmalloc()第一个参数是要分配的块的大小,第一个参数为分配标志,用于控制kmalloc()的行为. km ...

  2. XV6学习笔记(2) :内存管理

    XV6学习笔记(2) :内存管理 在学习笔记1中,完成了对于pc启动和加载的过程.目前已经可以开始在c语言代码中运行了,而当前已经开启了分页模式,不过是两个4mb的大的内存页,而没有开启小的内存页.接 ...

  3. Python基础教程学习笔记:第一章 基础知识

    Python基础教程 第二版 学习笔记 1.python的每一个语句的后面可以添加分号也可以不添加分号:在一行有多条语句的时候,必须使用分号加以区分 2.查看Python版本号,在Dos窗口中输入“p ...

  4. COCOS学习笔记--Cocod2dx内存管理(三)-Coco2d-x内存执行原理

    通过上两篇博客.我们对Cocos引用计数和Ref类.PoolManager类以及AutoreleasePool类已有所了解,那么接下来就通过举栗子来进一步看看Coco2d-x内存执行原理是如何的. / ...

  5. 嵌入式linux学习笔记1—内存管理MMU之虚拟地址到物理地址的转化

    一.内存管理基本知识 1.S3C2440最多会用到两级页表:以段的方式进行转换时只用到一级页表,以页的方式进行转换时用到两级页表.页的大小有三种:大页(64KB),小页(4KB),极小页(1KB).条 ...

  6. Linux内核学习笔记——内核内存管理方式

    一 页 内核把物理页作为内存管理的基本单位:内存管理单元(MMU)把虚拟地址转换为物理 地址,通常以页为单位进行处理.MMU以页大小为单位来管理系统中的也表. 32位系统:页大小4KB 64位系统:页 ...

  7. ios学习笔记之内存管理

    一,内存管理类型定义      1,基本类型  任何C的类型,eg:      int,short,char,long,long long,struct,enum,union等属于基本类型或结构体   ...

  8. Cocos2D-X2.2.3学习笔记3(内存管理)

    本章节介绍例如以下: 1.C/C++内存管理机制 2.引用计数机制 3.自己主动释放机制 1.C/C++内存管理机制 相信仅仅要懂oop的都知道NEW这个keyword吧,这个通俗点说事实上就是创建对 ...

  9. arm-linux学习笔记3-linux内存管理与文件操作

    配置好linux系统之后需要vim配置一下,有助于我们的编程,主要的配置如下 在/etc/vim/vimrc文件中 "显示行号 set number "自动缩进 set autoi ...

  10. 《C#高级编程》学习笔记----c#内存管理--栈VS堆

    本文转载自Netprawn,原文英文版地址 尽管在.net framework中我们不太需要关注内存管理和垃圾回收这方面的问题,但是出于提高我们应用程序性能的目的,在我们的脑子里还是需要有这方面的意识 ...

随机推荐

  1. sql命令查看,清楚mysql bin日志

    查看二进制日志文件 mysql> SHOW BINLOG EVENTS \G; mysql> SHOW MASTER LOGS; 清除二进制日志文件 mysql> PURGE { M ...

  2. Dynamic CRM 2013学习笔记(二十)字段改变事件的二种实现方法

    CRM里有二种方式实现字段change事件,一种是在form里,一种完全通过js来实现.本文介绍下二者的用途及区别. 1. Form里用法 这种方式估计其实也是添加一个js的function. 这种方 ...

  3. Asp.Net Web API 2第七课——Web API异常处理

    前言 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.html 本文主要来讲解Asp.Ne ...

  4. Oracle 删除大表中部分数据

    需求: 项目中有一张表大概有7000多万条数据,造成表空间已满,需要清理部分数据,打算清理3000万. 2B 做法: delete from table_name where ID > '400 ...

  5. [Java Web] 2、Web开发中的一些架构

    1.企业开发架构: 企业平台开发大量采用B/S开发模式,不管采用何种动态Web实现手段,其操作形式都是一样的,其核心操作的大部分都是围绕着数据库进行的.但是如果使用编程语言进行数据库开发,要涉及很多诸 ...

  6. 近期code review几处小问题集锦

    1 线程池使用不当 我们的调度系统需要将一堆会员分配给相应的人员来处理,流程如以下伪代码所示: public void dispatch() { while (true) { List<Memb ...

  7. BOM (Browser Object Model) 浏览器对象模型

    l对象的角色,因此所有在全局作用域中声明的变量/函数都会变成window对象的属性和方法; // PS:尝试访问未声明的变量会抛出错误,但是通过查询window对象,可以知道某个可能未声明的对象是否存 ...

  8. atitit.web的动态include 跟变量传递 java .net php

    atitit.web的动态include 跟变量传递 java .net php 1. 动态include  <jsp:include 1 2. 使用QueryString 1 3. 使用Ses ...

  9. Leetcode 342 Power of Four 数论

    题意:判断一个数是不是4的幂数,和Power of two类似. 先判断num是否大于0,再判断num是否能开根号,最后判断num开根号后的数是否是2^15的约数. 提示:4的幂数开根号就是2的幂数. ...

  10. Liferay7 BPM门户开发之36: 使用Portlet filters过滤器做切面AOP

    使用Portlet filters过滤器做切面AOP Portlet Filters定义于JSR286 Java Portlet Specification 2.0 Portlet Filters是为 ...