【OC基础】03-OC内存管理

概述

跟Java和C#类似,OC创建的对象在堆上。与Java和C#不同的是Java和C#有垃圾回收机制,所以不需要程序员手动释放堆上的内存。而OC没有垃圾回收机制,必须手动管理内存的创建和释放。下面介绍一下OC内存管理内存管理的方式。

引用计数器

OC管理内存的方式类似C++中的智能指针,创建一个对象时,在ObjC中每个对象内部都有一个与之对应的整数(retainCount),叫“引用计数器”,当一个对象在创建之后初始化它的引用计数器为1,当调用这个对象的alloc、retain、new、copy方法之后引用计数器自动在原来的基础上加1(ObjC中调用一个对象的方法就是给这个对象发送一个消息),当调用这个对象的release方法之后它的引用计数器减1,如果一个对象的引用计数器为0,则系统会自动调用这个对象的dealloc方法来销毁这个对象。

Student.h文件:

1 #import <Foundation/Foundation.h>
2
3 @interface Student : NSObject
4
5 #pragma mark - 属性
6 @property (nonatomic,copy)NSString *name;
7 @property (nonatomic,assign)float age;
8
9 @end

Student.m文件:

1 #import "Student.h"
2
3 @implementation Student
4
5 -(void)dealloc{
6     NSLog(@"Invoke Student dealloc method");
7     [super dealloc];
8 }
9 @end

main.m文件:

 1 #import <Foundation/Foundation.h>
 2 #import "Student.h"
 3 int main(int argc, const char * argv[])
 4 {
 5
 6     @autoreleasepool {
 7
 8         // insert code here...
 9         Student *stu = [[Student alloc]init];
10         stu.name=@"lisi";
11         stu.age=12;
12         NSLog(@"retainCount=%lu",[stu retainCount]);
13         //结果为1
14         [stu retain];
15         NSLog(@"retainCount=%lu",[stu retainCount]);
16         //结果为2
17         [stu release];
18         NSLog(@"retainCount=%lu",[stu retainCount]);
19         //结果为1
20         [stu release];
21         stu=nil;
22         [stu release];
23     }
24     return 0;
25 }

我们可以看出,在创建一个对象之后,初始化引用计数器为1,retain之后,计数器增加1,然后每release一次,计数器都会减1,直到这个对象被释放。

内存释放的原则

对象之间引用可以是复杂的,有时候会出现相互引用既循环引用的情况,所以对象的释放不能紧紧依靠自动化来完成。内存释放的原则是谁创建,谁释放。如下:

Book.h:

1 #import <Foundation/Foundation.h>
2
3 @interface Book : NSObject
4 @property (nonatomic,copy) NSString *bookName;
5 -(void)read;
6 -(id)initWithName:(NSString*) bname;
7 @end

Book.m

 1 #import "Book.h"
 2
 3 @implementation Book
 4 -(void)read{
 5     NSLog(@"now read this book %@...",self.bookName);
 6 }
 7 -(id)initWithName:(NSString*) bname{
 8     [super init];
 9     _bookName=bname;
10     return self;
11 }
12 -(void)dealloc{
13     NSLog(@"Invoke book %@ dealloc method...",self.bookName);
14     [super dealloc];
15 }
16 @end

Student.h

 1 #import <Foundation/Foundation.h>
 2 #import "Book.h"
 3 @interface Student : NSObject{
 4     Book *_book;
 5 }
 6
 7 #pragma mark - 属性
 8 @property (nonatomic,copy)NSString *name;
 9 @property (nonatomic,assign)float age;
10 -(id)initWithNameAndAge:(NSString*)sname andAge:(float) sage;
11 -(void)setBook:(Book*)book;
12 -(Book*)book;
13 @end

Student.m

 1 #import "Student.h"
 2
 3 @implementation Student
 4
 5 -(id)initWithNameAndAge:(NSString *)sname andAge:(float)sage{
 6     self.name=sname;
 7     self.age=sage;
 8     return self;
 9 }
10 -(void)setBook:(Book *)book{
11     if (_book!=book) {
12         [_book release];
13         _book = [book retain];
14     }
15 }
16
17 -(Book*)book{
18     return _book;
19 }
20
21 -(void)dealloc{
22     NSLog(@"Invoke Student dealloc method");
23     [_book release];
24     [super dealloc];
25 }
26 @end

main.m

 1 #import <Foundation/Foundation.h>
 2 #import "Student.h"
 3 int main(int argc, const char * argv[])
 4 {
 5
 6     @autoreleasepool {
 7
 8         // insert code here...
 9         Student *stu = [[Student alloc]initWithNameAndAge:@"sili" andAge:12];
10
11         Book *book1 = [[Book alloc]initWithName:@"AAA"];
12         [book1 release];
13         [stu.book read];
14
15         Book *book2 = [[Book alloc]initWithName:@"BBB"];
16         [stu setBook:book2];
17         [book2 release];
18         [stu.book read];
19         [stu release];
20     }
21     return 0;
22 }

运行结果:

1 2015-05-03 11:59:24.939 first[1814:303] Invoke book AAA dealloc method...
2 2015-05-03 11:59:24.941 first[1814:303] now read this book BBB...
3 2015-05-03 11:59:24.942 first[1814:303] Invoke Student dealloc method
4 2015-05-03 11:59:24.942 first[1814:303] Invoke book BBB dealloc method...

属性参数

其实我们可以直接利用OC提供的属性来达到同样的效果:

@property (nonatomic,retain)Book *book;

属性包含的所有参数和用法如下:

如果不进行设置或者只设置其中一类参数,程序会使用三类中的各个默认参数,默认参数:(atomic,readwrite,assign)。一般情况下如果是基本类型使用assign,非字符串对象使用retain,字符串对象使用copy。原子性和读写属性根据需要设置即可。

自动释放池

自动内存释放使用@autoreleasepool关键字声明一个代码块,如果一个对象在初始化时调用了autorelase方法,那么当代码块执行完之后,在块中调用过autorelease方法的对象都会自动调用一次release方法。

 1 #import <Foundation/Foundation.h>
 2 #import "Student.h"
 3 int main(int argc, const char * argv[])
 4 {
 5
 6     @autoreleasepool {
 7
 8         // insert code here...
 9         Student *stu = [[Student alloc]initWithNameAndAge:@"lisi" andAge:12];
10         Student *stu1 = [[[Student alloc]initWithNameAndAge:@"wanger" andAge:14]autorelease];
11         [stu1 retain];
12         [stu autorelease];
13     }
14     return 0;
15 }

打印结果:

1 2015-05-03 12:27:39.949 first[1938:303] Invoke Student dealloc lisi method

我们可以看出,stu对象被完全释放,而stu1没有被释放,这是因为每个对象的release方法只被调用了一次,而stu1的引用计数为2,所以在代码块结束的时候stu1对象不会被释放(造成了内存泄露)。对于自动内存释放有以下几点需要注意:

  1. autorelease方法不会改变对象的引用计数器,只是将这个对象放到自动释放池中;
  2. 自动释放池实质是当自动释放池销毁后调用对象的release方法,不一定就能销毁对象(如果对象的引用计数器>1,就无法销毁);
  3. 由于自动释放池最后统一销毁对象,因此如果一个操作比较占用内存(对象比较多或者对象占用资源比较多),最好不要放到自动释放池或者考虑放到多个自动释放池;
  4. ObjC中类库中的静态方法一般都不需要手动释放,内部已经调用了autorelease方法;
时间: 2024-10-22 19:55:50

【OC基础】03-OC内存管理的相关文章

OC基础 05-手动内存管理(MRC)

---恢复内容开始--- MRC: Manul(手动) Reference(引用) Counting(计数) 什么是手动引用计数? 所有对象的内容都需要我们手动管理, 需要程序员自己编写release/retain等代码 内存管理的原则就是有加就有减 也就是说, 一次alloc/new/copy对应一次release, 一次retain对应一次relese 内存管理的重要性: 移动设备的内存极其有限,每个app的占用内存也是有限制的. 当我们创建一个OC对象,定义一个变量,调用一个函数或者方法,

黑马程序员---OC基础6【内存管理】【手动内存管理】【单、多个对象的内存管理】【*@property参数】【@class的使用】【NSString类的内存管理】【autorelease使用】

------- iOS培训.Android培训.Java培训.期待与您交流! ---------- [内存管理] 1.内存管理概念 由于移动设备内存及其有限,所以每个app所占的内存也是有限的 需要回收一些不使用的空间 2.OC内存管理的范围 管理任何继承NSOject的对象,对其他的基本数据类型无效 主要管理堆区中的对象的内存管理   3.内存管理的原理 1)对象所有权概念 任何对象都可以能拥有一个或多个所有者,只要一个对象至少还拥有一个所有者,他就会继续存在 cocoasu所有权策略 任何自

七.OC基础加强--1.内存管理 2.野指针,内存泄露 3.set方法的内存管理 [email&#160;protected]参数 [email&#160;protected]和循环retain的使用 6.NSString的内存管理

1,内存管理简单介绍 1,为什么要有内存管理? malloc selloc dealloc```需要回头复习 一般的内存 4s 是512m内存:6 是1024m内存: 当内存过大时,会耗尽内存.出现程序闪退. 2.OC内存管理的范围 : 管理任何继承NSObject的对象,对其他的基本数据类型无效. 3.对象类型是程序运行过程中动态分配的,存储在堆区:内存管理主要是对 堆区中的对象的内存管理. 4.OC内存管理的原理 为了防止内存泄露 对象的引用计数器 : 每个OC对象都有自己的引用计数器,是一

OC基础15:内存管理和自动引用计数

1.什么是ARC? (1).ARC全名为Automatic Reference Counting,即是自动引用计数,会自动统计内存中对象的引用数,并在适当时候自动释放对象: (2).在工程中使用ARC非常简单:只需要像往常那样编写代码,只不过永远不用写retain. release和autorelease三个关键字: (3).在使用ARC之前,需要手动管理内存计数,这种机制称为MRC,即是手动引用计数 (Manual Referecen Counting): (4).ARC是Objective-

iOS开发OC基础:OC的内存管理

OC内存管理的基础知识 /** //             *  当对一个对象autorelease时,会将该对象放到离它最近的自动释放池,当自动释放池将要销毁时,会对自动释放池中的对象发送release消息,让对象的引用计数减1,(切记,是将对象的引用计数减1,而不是回收空间.) //             */ /** *  如果相对一个对象做copy操作,就必须让该类服从NSCopying协议,并且实现协议中的- (id)copyWithZone:(NSZone *)zone方法 */

iOS开发OC基础:OC属性的一些概念和基本使用

一.属性简介 //属性是OC2.0之后新出的一种语法,能让我们快速的生成setter以及getter方法,大大简化代码 二.如何定义一个属性 //@property 属性关键字,用来定义属性 //NSString * 属性的类型 //name 属性的名字. //@property 只是生成的setter以及getter方法的声明.@property NSString *name; 三.属性的使用注意事项//如果在.m文件中我们自己实现了setter以及getter方法,则编译器就不会再帮我们生成

iOS开发OC基础:OC基础概念总结,OC面向对象的思想

一.什么是OOP: OOP(Object Oriented Programming):面向对象编程 二.面向对象和面向过程的区别: 面向过程编程:分析解决问题的步骤,实现函数,依次使用面向对象编程:分解问题组成的对象,协调对象间的联系和通信,解决问题. 面向过程是以事件为中心,关心的是完成这个事件的详细步骤:面向对象是以事物为中心,关心的是事物应该具备的功能,而完成一个事件只是事物所有功能里面的一个小功能(以过程为中心,以对象为中心) 三.类和对象 对象定义了解决问题的步骤中的行为,不刻意完成一

iOS开发OC基础:OC中的分类(类目)

//分类,category,(类目) //为没有源代码的类添加方法 //一定要注意,只能添加方法,不能添加实例变量 /** *  分类 类的定义也是分为接口部分和实现部分 接口部分:以@interface开头 + 类名 后跟小括号,小括号内填写的是分类名 @end结束 在@interface 与@end 之间添加方法. */ //分类为原类添加的方法,就相当于原类具有该方法,可以正常调用 因为涉及到几个分类的创建,所以就直接上传代码了,其实代码也不多,只是怕大家在建立分类的时候会混淆,所以直接把

iOS开发OC基础:OC中的协议

1.协议是一种为有源代码的类扩充方法的方式. 2.协议只是一系列方法的生命,就相当于一张任务清单,规定了要做的事情,但是具有的实施(也就是实现),是由服从该协议的类来实现.所以协议只有.h文件,并且不可以定义变量 3.协议的定义是以@protocol开头, + 协议的名字 <>(表示服从的协议)服从的协议写在<>之内,多个协议之间通过逗号来进行分隔,父协议中的内容就相当于子协议也具有这些内容,以@end结束. 下面的附件是协议的一个小例子,可以加深大家对协议的理解,看完之后一定要多