内存管理

主要内容

1.内存管理的概念

2.引用计数

3.如何持有对象所有权

4.自动释放池

5.@property的使用

什么是内存管理

内存管理是关于如何管理对象生命周期的编程原则。

int main(int argc, char *argv[])

{

int value = 100;

Dog *mydog = [[Dog alloc]init];

[dog setNum:@"蓝眼儿"];

return 0

}

栈区

value 100

person 0x12345

堆区

Dog对象

_name

oc中的内存管理只针对oc中的对象,所有对象都继承NSObject

基本数据类型不需要管理内存。

当一个对象没有人再使用,该对象应该从内存中销毁掉。

引用计数

所有oc对象都有一个计数器,这个计数器我们称为引用计数。

引用计数表示有几个人在使用当前对象。

NSObject对象

retainCount

引用计数

每个对象都有一个retainCount引用计数器,表示当前对象被引用的数量。

怎么是引用计数器加减呢?

1.调用retain方法, 计数+1,调用release方法,计数-1

2.当引用计数为0时,说明没有人使用此对象,此对象会被系统销毁。

alloc   retain       release

alloc用来创建对象,创建完成后,引用计数为1,只调用一次。

retain使引用计数+1,可以调用多次。

release使引用计数-1,可以调用多次。

当引用计数为0时,对象会被系统从内存中销毁,销毁之前,会自动调用此对象的dealloc方法。

retain, release示例

Person *person = [[Person alloc]init];//计数器为1

[person retain];//计数器为2

[person retain];//计数器为3

[person release];//计数器为2

[person release];//计数器为1

[person release];//计数器为0,对象从内存中销毁,调用dealloc方法。

为什么使用引用计数

遛狗的例子

对象所有权

当一个所有者(owner,本身是一个oc对象)做了如下动作,它就拥有了一个对象的所有权(ownership)

alloc                          retain                [mutable]copy

使用如下方法

release             autorelease

黄金法则

如果对一个对象使用了alloc,[mutable]copy, retain, 那么你必须使用相应的release或者autorelease释放。

如何持有对象

实例分析:如何让人持有狗的对象所有权

1.set方法持有对象的所有权

-(void)setDog: (Dog *)dog

{

       if (_dog!=dog) {

              [_dog release];

              _dog = [dog retain];

       }

}

2.自定义初始化方法,持有对象的所有权

 -(id) initWithDog: (Dog *)dog

 {

        self = [super init];

        if (self != nil) {

               _dog = [dog retain];

        }

        return self;

 }

dealloc方法

当对象的引用计数为0时,系统调用此对象dealloc。

我们应该在dealloc方法中,释放他持有的对象。

-(void)dealloc

{

[_dog release];

[_car release];

[super release];//为了释放父类持有的对象所有权。

property的使用

有一个类有如下属性

@interface User:NSObject

{

int userId;

NSString *_userName;

NSString *_passwd;

NSString *_email;

NSString *_birthday;

}

设置器

 -(void) setUserName: (NSString *)name

 {

        _name = name;

 }

 -(NSString *)userName{

        return _name;

 }

每个属性都这样写set和get方法是很麻烦的。

property可以自动生成一个get和set方法,不需要我们手动编写

@interface User : NSObject

{

//不必在定义,@property自动生成

}

@property(nonatomic, retain) NSString *userName;

使用方法

@property(<1>nonatomic,<2>retain,<3>readwrite)NSString *userName;

1.原子性:

atomic:多线程模式下存在线程保护,默认

nonatomic:多线程模式下不存在线程保护

2.赋值

assign:直接赋值,默认

-(void)setUserName: (NSString *)name

{

_name = name;

}

retain:保留原对象

-(void)setUserName: (NSString *)name

{

if (_name != name) {

[_name release];

_name = [name retain];

}

}

copy:拷贝对象

-(void)setUserName: (NSString *)name

{

if (_name != name) {

[_name release];

_name = [name copy];

}

}

3.读写性

readwrite:生成getter,setter方法,默认

readonly:只生成getter方法

注意,我们也可以重新实现set和get方法,优先调用自己实现的set和get方法。

实战

1.理解引用计数,对象所有权,理解oc内存管理的机制。

2.设计如下几个类,Car自定义初始化方法,初始化方法传入引擎对象和车灯对象。当车启动的时候,会调用引擎转动,车灯亮灯,当车停止的时候调用引擎停止转动,车灯熄灭。(注意内存管理)

Car(汽车)

Engine(引擎)

lamp(车灯)

属性:

属性:

属性:

名字(name)

型号(model)

瓦数(wattage)

车牌号(licence)

排量(capacity)

方法:

引擎(engine)

方法:

亮(light)

车灯(lamp)

转动(turn)

熄灭(dark)

方法:启动(run)

停止转动(stopTurn)

停止(stop)

数组的内存管理

如果一个对象被添加到数组,那么这个对象的引用计数会变化吗?

NSMutableArray *mutableArray = [NSMutableArray array];

Dog *dog1 = [[Dog alloc]init];

Dog *dog2 = [[Dog alloc]init];

[array addObject: dog1]; //dog1会被数组retain,计数+1

[array addObject:dog2];dog2会被数组retain计数+1

[dog1 release];

[dog2 release];

数组销毁,或者removeAllObjects,会给每一个元素发送release消息。

[array release];

//移除下标为1的元素,同时向它发送release消息

[array removeObjectAtIndext:1];

自动释放池

自动释放池是oc的一种内存自动管理机制。

当自动释放池销毁时,它会对池子中每一个对象调用一次release方法。

当我们向一个对象autorelease消息时,这个对象就会被放入自动释放池。

老的写法

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

User *user = [[user alloc]init];

//加入自动释放池

[user autorelease];

//自动释放池销毁

[pool release];

新语法的写法

@autorelesepool {

User *user = [[User alloc]init];

//加入自动释放池

[user autorelease];

}

自动释放池的原理

自动释放池就像一个数组,容纳了许多加入池的对象。

对象1

对象2

对象3

自动释放池可以嵌套使用

autorelease会将对象添加到离他最近的自动释放池中。

NSAutoreleasePool pool1 = [[NSAutoreleasePool alloc]init];

Person *person = [[Person alloc]init];

//添加到离他最近的pool1中

[person autorelease];

NSAutoreleasePool pool2 = [[NSAutoreleasePool alloc]init];

Dog *dog = [[Dog alloc]init];

[dog autorelease];

[pool2 release];

[pool1 release];

典型错误例子,如下代码有内存泄漏

[person setDog:[[Dog]alloc]init];

正确的写法是:

Dog *dog = [[[Dog alloc]init]release];

[person setDog:dog];

//这里不能[dog release]

错误的典型例子

-(NSString *)getInfo {

NSString *info = [[NSString alloc]initWithFormat:@"姓名:%s年龄:%d", _name, _age];

[info release];//返回的对象已经销毁

return info;

}

NSString *infoString = [person getInfo];

[infoString release];//违背了黄金法则

正确的写法是

-(NSString *)getInfo {

NSString *info = [[NSString alloc]initWithFormat:@"姓名:%s年龄:%d", _name, _age];

return [info autorelease];

}

NSString *infoString = [person getInfo];

//自动释放池销毁的时候,会向infoString对象发送release消息。

举例

for (i = 0; i < 1000000; i++) {

NSMutableArray *array = [[NSMutableArray alloc]init];

[array autorelease];

}

循环100万次,创建100万个对象,这些对象在该循环体内不会自动销毁,只会加到最近的自动释放池中。只有当自动释放池销毁了,100万个对象才会受到release消息。这样100万个对象同时存在内存当中,占用内存很大。

更好的写法是

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

for (i = 0; i < 1000000; i++) {

if (i % 1000 == 0) {

[pool release];

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

}

NSMutableArray *array = [[NSMutableArray alloc]init];

[array autorelease];

}

该代码每执行1000次就会把pool释放一次,同时在穿件一个新的自动释放池。也就是累计不会超过1000个对象。

类方法创建的内存管理

+(Dog *)dog {

Dog *dog = [[Dog alloc]init];

return [dog autorelease];

};

Dog *dog = [Dog dog];

[person setDog: dog];

//这里不能[dog release];

类方法创建的内存管理

Foundation中的类可以通过alloc创建和类方法创建,区别在于内存管理不一样。

类方法创建的对象是加入了自动释放池

//alloc创建

NSArray *array = [[NSArray alloc]init];

//其他方法

[array release];

//类方法创建, 加入了自动释放池

NSArray *arr = [NSArrary array];

//不能再用[arr release];

新语法创建的内存管理

新语法创建的对象和类方法创建的对象相同,由自动释放池管理

NSArray *array = @[@“zhngsan”,  @”lisi”];

NSNumber *number = @123;

常见的错误

1.错误

+(id) person{

Person *person = [[Person alloc]init];

[person release];

return person;

}

正确的写法

+(id)person {

Person *person = [[Person alloc]init];

return [person autorelease];

}

2.错误

+(void)description

{

NSString *string = [NSString stringWithFormat:@”lrz”];

[name release];

NSLog(“name:%@”, string);

}

正确

+(void)description

{

NSString *string = [NSString stringWithFormat:@”lrz”];

NSLog(“name:%@”, string);

}

3.错误

Laptop *laptop = [[Laptop alloc]init];

laptop.name = [NSString stringWithFormat:@”apple”];

NSArray *array = [NSArray arrayWithObject: laptop];

[array release];

正确

Laptop *laptop = [[Laptop alloc]init];

laptop.name = [NSString stringWithFormat:@”apple”];

NSArray *array = [NSArray arrayWithObject: laptop];

[laptop release];

4.错误

-(void)memory

{

Car *car = [[Car alloc]init];

if (gas == 0) {

return;

}

[car release];

}

正确

-(void)memory

{

Car *car = [[[Car alloc]init]autorelease];

if (gas == 0) {

return;

}

}

ARC

自动引用计数(automatic reference counting),提供自动管理内存的功能。

不需要手动管理引用计数,不需要也不允许retain, release, autorelease

注意版本的支持是在IOS4(不支持弱引用),ios5上

循环引用

对象A retain对象B。同时对象B retain对象A,这种情况我们称之为循环引用。

循环引用会导致两个对象都无法销毁掉。

-(void)setA: (A *a)

{

       if (_a!=a) {

[_a release];

_a = [a retain];

}

}

-(void)setB:(B *b)

{

       if (_b != b) {

              [_b release];

              _b = [b retain];

}

}

Object-c 内存管理的更多相关文章

  1. 12.Object-C--浅谈OC的内存管理机制

    昨天学习了OC的内存管理机制,今天想总结一下,所以接下来我要在这里bibi一下:OC的内存管理. 首先我要说的是,内存管理的作用范围. 内存管理的作用范围: 任何继承了NSObject的对象,对其他基 ...

  2. .NET基础拾遗(1)类型语法基础和内存管理基础

    Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开发基 ...

  3. cocos2d-x内存管理

    Cocos2d-x内存管理 老师让我给班上同学讲讲cocos2d-x的内存管理,时间也不多,于是看了看源码,写了个提纲和大概思想 一.   为什么需要内存管理 1. new和delete 2. 堆上申 ...

  4. iOS开发系列—Objective-C之内存管理

    概述 我们知道在程序运行过程中要创建大量的对象,和其他高级语言类似,在ObjC中对象时存储在堆中的,系统并不会自动释放堆中的内存(注意基本类型是由系统自己管理的,放在栈上).如果一个对象创建并使用后没 ...

  5. Android 内存管理 &Memory Leak & OOM 分析

    转载博客:http://blog.csdn.net/vshuang/article/details/39647167 1.Android 进程管理&内存 Android主要应用在嵌入式设备当中 ...

  6. Python深入06 Python的内存管理

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 语言的内存管理是语言设计的一个重要方面.它是决定语言性能的重要因素.无论是C语言的 ...

  7. 【转】iOS夯实:ARC时代的内存管理

    iOS夯实:ARC时代的内存管理 什么是ARC Automatic Reference Counting (ARC) is a compiler feature that provides autom ...

  8. 理解 iOS 的内存管理

    远古时代的故事 那些经历过手工管理内存(MRC)时代的人们,一定对 iOS 开发中的内存管理记忆犹新.那个时候大约是 2010 年,国内 iOS 开发刚刚兴起,tinyfool 大叔的大名已经如雷贯耳 ...

  9. Objective-C内存管理之-引用计数

    本文会继续深入学习OC内存管理,内容主要参考iOS高级编程,Objective-C基础教程,疯狂iOS讲义,是我学习内存管理的笔记 内存管理 1 内存管理的基本概念 1.1 Objective-C中的 ...

  10. 内存管理内幕mallco及free函数实现

    原文:https://www.ibm.com/developerworks/cn/linux/l-memory/ 为什么必须管理内存 内存管理是计算机编程最为基本的领域之一.在很多脚本语言中,您不必担 ...

随机推荐

  1. MATLAB的三维散点图

    MATLAB中三维散点图函数为scatter3(x,y,z) 三维火柴图为stem3(x,y,z)

  2. WEB开发最佳实践

    linux命令 man ls:显示ls的命令详情,man命令可以查具体的命令详情

  3. ubuntu10.04配置XMAPP中的环境变量

    1. 显示环境变量:[root@localhost ~]# echo $PATH/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/lo ...

  4. 学习篇:TypeCodes的2015年博客升级记

    原文: https://typecodes.com/mix/2015updateblog.html 2015年博客升级记 作者:vfhky | 时间:2015-05-23 17:25 | 分类:mix ...

  5. React的井字过三关(2)

    这篇笔记是官方教程的延续笔记,所有代码基于第一篇笔记的结尾代码.旨在解决教程后面提出的五个问题. 一 . 用(X,Y)来取代原有的数字坐标 原来的数字坐标是这样的: 现在的要求是把原来的代码坐标改为二 ...

  6. hibernate中java类的成员变量类型如何映射到SQL中的数据类型变化

    hibernate映射文件??.hbm.xml配置映射元素详解--Hibernate映射类型 在从Hibernate的java的成员类型映射到SQL中的数据类型,其内映射方式它满足,SQL可以自己调制 ...

  7. Python *与** 参数问题

    问题:     Python的函数定义中有两种特殊的情况,即出现*,**的形式.     如:def myfun1(username, *keys)或def myfun2(username, **ke ...

  8. 群集中的MS DTC分布式事务协调器

    MS DTC在大多数SQL 服务器下都需要安装,若只是安装数据库引擎或Analysis 服务可不安装DTC.如果后需要使用分布式事务,则可在SQL Server群集安装完成后再安装DTC. 一.群集M ...

  9. [Storm] 并发度的理解

    Tasks & executors relation Q1. However I'm a bit confused by the concept of "task". Is ...

  10. Javascript面向对象特性实现封装、继承、接口详细案例——进级高手篇

    Javascript面向对象特性实现(封装.继承.接口) Javascript作为弱类型语言,和Java.php等服务端脚本语言相比,拥有极强的灵活性.对于小型的web需求,在编写javascript ...