黑马程序员-IOS基础之OC内存管理

------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------


内存管理

01、为什么要内存管理?
       内存管理可谓是OC里面最重要的环节,因为早前开发ios程序的,在网上没有学习资源,就去买相关的书籍,自己就去摸索,当时只注重功能的实现,没有重视内存管理,所以那时候的好多开发者都在内存管理上吃了不少亏。开发者如果不重视内存管理,在写代码的过程中,就会发现写一行就报一个错,写一行又报一个错,但是编译器和链接器是不会报错的(只要语法没有问题),所以就是内存没有管理好,内存泄露了。
       那么什么是内存管理呢?我们一款移动设备的内存是极其有限的,如iPhone4或iPhone4s的内存只有512兆,既然只有这么一点内存,那我们每一个应用程序所占的内存就得限制一下(一个应用程序默认的内存就只有几十兆),一旦你的应用程序占用的内存超过了这几十兆,系统就会给应用程序发出内存警告。此时,你接收到系统发出的内存警告,你应该尽量的回收那些你不使用的对象,如果还占用这些内存空间,应用程序可能就会强制退出。

内存管理如图:
栈内存中的变量,系统都会自动回收,而堆中Person对象只有当程序结束后,才会回收。

总结
1、移动设备的内存极其有限,每个App所占用的内存是有限制的。
2、当App所占用的内存较多时,系统就会发出内存警告,这时就得回收一些不需要再使用的内存空间,比如回收一些不需要使用的对象
3、管理范围:任何继承了NSObject的对象。对其他基本数据类型(int、char、float、double、struct、enum等)无效。因为基本数据类型的变量存储在内存的栈区中,系统会自动回收这些变量。但对象是存放在内存的堆中,需要程序员手动的释放。


02、引用计数器

        接上面的例子,尽管我们栈中没有指针指向我们的Person对象,所以我们的Person对象就会一直占用我们的内存空间。那么我们怎么知道Person对象什么时候回收呢?

1、每个OC对象都有自己的引用计数器,是一个整数,表示“对象被引用的次数”。即有多少人正在使用这个OC对象。
2、每个OC对象内部专门有4个字节的存储空间来存储引用计数器。

引用计数器的作用
1、当使用alloc、new或者copy创建一个新对象是,新对象的引用计数器默认就是1
2、当一个对象的引用计数器值为0时,对象占用的内存就会被系统回收。换句话说,如果对象的计数器不为0,那么在整个程序运行过程中,它占用的内存就不可能被回收,除非整个程序已经退出。


引用技术全球的操作
1、给对象发送一条retain消息,可以使引用计数器值+1(retain方法返回对象本身)。
2、给对象发送一个release消息,可以使引用计数器值-1。
3、可以给对象发送retainCount消息,可以获得当前的引用计数器的值。


对象的销毁
1、当一个对象的引用计数器值为0时,那么它将被销毁,其占用的内存被系统回收。
2、当一个对象被销毁时,系统会自动向对象发送一条dealloc消息。
3、一般会重写dealloc方法,在这里释放相关资源,dealloc就像对象的遗言。
4、一旦重写了dealloc方法,就必须调用[super dealloc],并且放在最后面调用。
5、不要直接调用dealloc方法。
6、一旦对象被回收了,它占用的内存就不再可用,坚持使用会导致程序崩溃(野指针错误)。

代码如下:

Person类文件

@interface Person : NSObject
{
    int _age;
}

- (void)setAge:(int)age;
- (int)age;
@end


#import <Person.h>

@implementation Person

- (void)setAge:(int)age;
{
    _age = age;
}

- (int)age
{
    return _age;
}

//当一个Person对象被回收的时候,就会自动调用这个方法。
- (void) dealloc
{
    NSLog(@"Person对象被回收!");
    
    //super的dealloc方法一定要调用,而且放在最后面。
    [super dealloc];
}

@end

main.m文件中

#import <Foundation/Foundation.h>
#import "Person.h"

int main()
{
    //[Person alloc]为对象分配内存,init只是给对象初始化,所以对对象引用计数器没有影响。
    //对象被创建成功,默认计数器为1
    Person *p = [[Person alloc] init];

    //查看对象引用计数器的值,使用retainCount,它的返回值是NSUInteger,其实就是unsigned long类型。
    USInteger c = [p retainCount];

    //打印一下对象引用计数器的值是多少。
    NSLog(@"计数器:%ld",c);

    //计数器变为2,retain方法返回的是对象本身。所以要让person对象回收,就还得release
    p = [p retain];
    
    //计数器变为1
    [p release];

    //计数器变为0 
    [p release];

    //本来上面就可以回收对象了,但是如果再加上几条release代码
    //这样就会报错。野指针错误 EXC_BAD_ACCESS
    [p release];
    [p release];

    //-[p retain]:message sent to deallocated instance...
    [p retain];//这个时候,会报错。

    //-[person setAge]:message sent to deallocated instance...
    //给已经释放的对象发送一条-sentAge消息:
    p.age = 10;//[p setAge:10]

    return 0;
}

       其他,对象被回收有两种方式,第一种,就是程序在运行的过程中我们程序员手动的回收,第二种就是程序结束后,将回收所有的内存。那么我们来验证一下,对象是否被回收。我们知道对象被回收的时候,会调用自己的dealloc方法,所以我们重写对象的dealloc方法,来验证我们对象是否被回收。
所以,只要是有alloc,就要有release,只要有retain,就要有release。

总结:
1、方法的基本使用
1> retain:计数器+1,会返回对象本身。
2> release:计数器-1,没有返回值。
3> retainCount:获取当前的计数器。
4> dealloc:当一个对象要被回收的时候,就会调用,一定要放在最后面调用[super dealloc]。


2、概念
1> 僵尸对象:所占用内存已经被回收的对象,僵尸对象不能使用。
2> 野指针:指向僵尸对象(不可用内存)的指针。
3> 空指针:没有指向任何东西的指针(存储的东西是nil、NULL、0)
   给空指针发送消息不会报错。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值