OC语言之内存管理简介

来源:互联网 发布:英国贝德福德大学 知乎 编辑:程序博客网 时间:2024/06/01 19:14

# 内存管理简介

##1.内存管理的重要性

- 移动设备的内存极其有限,每个app所能占用的内存是有限制的

- 下列行为都会增加一个app的内存占用

    +创建一个OC对象

    +定义一个变量

    +调用一个函数或者方法

- 当app所占用的内存较多时,系统会发出内存警告,这时得回收一些不需要再使用的内存空间。比如回收一些不需要使用的对象、变量等

- 如果app占用内存过大, 系统可能会强制关闭app,造成闪退现象, 影响用户体验

---

##2.什么是内存管理

-如何回收那些不需要再使用的对象?

    +那就得学会OC的内存管理

- 所谓内存管理, 就是对内存进行管理, 涉及的操作有:

    +分配内存 : 比如创建一个对象, 会增加内存占用

    +清除内存 : 比如销毁一个对象, 能减小内存占用

- 内存管理的管理范围

    +任何继承了NSObject的对象

    +对其他非对象类型无效(int、char、float、double、struct、enum等 )

- 只有OC对象才需要进行内存管理的本质原因

    +OC对象存放于堆里面

    +非OC对象一般放在栈里面(栈内存会被系统自动回收)

---

##3.堆和栈

- 栈(操作系统):由操作系统自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈(先进后出);

- 堆(操作系统):一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收,分配方式类似于链表。

- 示例:

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

{

   @autoreleasepool {

       int a = 10; // 栈

       int b = 20; // 栈

       // p : 栈

       // Person对象(计数器==1) : 堆

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

    }

   // 经过上一行代码后, 栈里面的变量a\b\c都会被回收

   // 但是堆里面的Person对象还会留在内存中,因为它是计数器依然是1

   return 0;

}

```

![](http://7xj0kx.com1.z0.glb.clouddn.com/dhz.png)

[更多关于堆栈信息](http://baike.baidu.com/link?url=VJz-vKfY_ASVHCB17nWR_uQ4Adhuasl2WOrW4O7ZgFdgq5Tl_kBGfUYzbNSzkSBkHAbAH8qzfDpl5Wm4rxQ1Ka)

 

# 野指针\空指针

##1.僵尸对象

- 已经被销毁的对象(不能再使用的对象)

##2.野指针

- 指向僵尸对象(不可用内存)的指针

- 给野指针发消息会报EXC_BAD_ACCESS错误

##3.空指针

- 没有指向存储空间的指针(里面存的是nil, 也就是0)

- 给空指针发消息是没有任何反应的

- 为了避免野指针错误的常见办法

+ 在对象被销毁之后, 将指向对象的指针变为空指针

 

# 内存管理原则

##1.内存管理原则

- 苹果官方规定的内存管理原则

    +谁创建谁release :

       * 如果你通过alloc、new或[mutable]copy来创建一个对象,那么你必须调用release或autorelease

    +谁retain谁release:

       * 只要你调用了retain,就必须调用一次release

- 总结一下就是

    +有加就有减

    +曾经让对象的计数器+1,就必须在最后让对象计数器-1

---

##2.多对象内存管理

- 单个对象的内存管理, 看起来非常简单

- 如果对多个对象进行内存管理, 并且对象之间是有联系的, 那么管理就会变得比较复杂

- 其实, 多个对象的管理思路 跟很多游戏的房间管理差不多

    +比如斗地主 \ 劲舞团 \ QQ音速

![](http://pic2.52pk.com/files/120414/534347_001415_6_lit.jpg)

- 总的来说, 有这么几点管理规律

    +只要还有人在用某个对象,那么这个对象就不会被回收

    +只要你想用这个对象,就让对象的计数器+1

    +当你不再使用这个对象时,就让对象的计数器-1

---

##3.set方法内存管理

- (1)retain需要使用的对象

- (2)release之前的对象

- (3)只有传入的对象和之前的不同才需要release和retain

```

- (void)setRoom:(Room *)room

{

   // 避免过度释放

   if (room != _room)

    {

       // 对当前正在使用的车(旧车)做一次release

       [_room release];

       // 对新车做一次retain操作

        _room = [room retain];

    }

}

```

##4.dealloc方法的内存管理

```

- (void)dealloc

{

   // 当人不在了,代表不用房间了

   // 对房间做一次release操作

    [_roomrelease];

   [super dealloc];

}

```

# @Property练习

##1.@Property练习

- 微博类(Status)

    +文字内容(text)

    +配图(picture)

    +发表时间(createTime)

    +作者(author)

    +转发的说说(repostStatus)

    +评论数(commentCount)

    +转发数(retweetCount)

    +赞数(likeCount)

 

- 作者类(Author)

    +昵称(name)

    +头像(icon)

    +生日(birthday)

    +账号(account)

 

- 账号(Account)

    +账号名称(name)

    +账号密码(pwd)

    +账号注册时间(registerTime)

 

```

模拟场景:

* 老王在2010-1-1 17:56:34注册了一个账号

(名称:xiaomage@520it.com,密码:haomage)

 * 老王的生日是1986-3-818:18:18

 * 老王发布一条说说

    * 文字内容  @“爆米花手机比逼格更有逼格”

    * 图片 @“phone.png”

    * 发表时间: 2015-6-20 10:23:23

    * 作者: 老王

    * 被转发的说说: 没有

    * 评论数: 100

    * 转发数: 90

    * 点赞数: 200

 * 王大锤在2012-8-819:26:54注册了一个账号

 (名称:dachuimeimei@520it.com, 密码:654321)

 * 王大锤的生日是1989-9-614:16:28

 * 王大锤在2015-6-2120:47:09时,转发了张三之前发布的说说,并且还附带了一句话:@“真的很有逼格”

![](http://www.youqudian.com/upload/you/others/2014/07/20140725150032_6gsf04q6.jpg)

---

# @class

##1.@class基本概念

- 作用

    +可以简单地引用一个类

- 简单使用

    +@class Dog;

    +仅仅是告诉编译器:Dog是一个类;并不会包含Dog这个类的所有内容

- 具体使用

    +在.h文件中使用@class引用一个类

    +在.m文件中使用#import包含这个类的.h文件

---

##2.@class其它应用场景

- 对于循环依赖关系来说,比方A类引用B类,同时B类也引用A类

- 这种嵌套包含的代码编译会报错

```

#import "B.h"

@interface A : NSObject

{

    B*_b;

}

@end

 

#import “A.h"

@interface B : NSObject

{

    A*_a;

}

@end

```

- 当使用@class在两个类相互声明,就不会出现编译报错

```

@class B;

@interface A : NSObject

{

    B*_b;

}

@end

 

@class A;

@interface B : NSObject

{

    A*_a;

}

@end

```

##3.@class和#import

- 作用上的区别

    +#import会包含引用类的所有信息(内容),包括引用类的变量和方法

    +@class仅仅是告诉编译器有这么一个类, 具体这个类里有什么信息, 完全不知

- 效率上的区别

    +如果有上百个头文件都#import了同一个文件,或者这些文件依次被#import,那么一旦最开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一遍 , 编译效率非常低

    +相对来讲,使用@class方式就不会出现这种问题了

---

# dealloc方法

##1.dealloc方法基本概念

- 当一个对象的引用计数器值为0时,这个对象即将被销毁,其占用的内存被系统回收

- 对象即将被销毁时系统会自动给对象发送一条dealloc消息

(因此, 从dealloc方法有没有被调用,就可以判断出对象是否被销毁)

- dealloc方法的重写

    +一般会重写dealloc方法,在这里释放相关资源,dealloc就是对象的遗言

    +`一旦重写了dealloc方法, 就必须调用[super dealloc],并且放在最后面调用

- 使用注意

    +不能直接调用dealloc方法

    +一旦对象被回收了, 它占用的内存就不再可用,坚持使用会导致程序崩溃(野指针错误)

0 0
原创粉丝点击