OC中关于对象的内存1

来源:互联网 发布:mac外置光驱安装win7 编辑:程序博客网 时间:2024/06/05 08:18


【转载学习】OC学习笔记之OC对象的内存管理


一、为什么要做内存管理
        相对于现在动不动就上T的硬盘外存来说,计算机的内存虽然也在提升在还是太小了,而现在的应用软件也十分吃内存,程序运行进程中如果不管理内存,如果有泄露,系统内存将会越用越小,对移动设备来说更是如此。苹果手机的内存只有那么大,如果应用程序不管理内存而占用了过多的内存,系统肯定是不允许的,引发的闪退给用户不好的体验,那这绝对算不上一个成功的应用开发。
        程序在运行中,应该及时销毁已经不需要的变量或者对象,及时释放内存,以维持内存占用的动态平衡。

二、OC内存管理的目标
        OC中内存管理的目标主要是任何继承根类NSObject后创建的OC对象,对基本数据类型我们不需要关心,系统可以自动回收。因为在内存中基本数据类型和OC对象的存放位置不同,前者是用栈存放,后者是用堆存放。
比如:int a = 1; int b = 2; Person *p = [[Person alloc] init];这几句代码在内存中的存放位置就分这两类。小桥这里回忆一MJ老师画过的图:
 

        如图所示,基本数据类型的变量是用栈来临时存放的,当过期的时候系统会自动回收,如下面的测试图片:

        上图说明,在main函数return之前,基本数据类型的变量占用的内存会自动被释放,而OC对象始终占用内存,注意:
这里的Person类型指针p也是基本类型,过期时也会被系统回收,这里的作用域是main函数,所以return之前,p指针变量还在。但是p所指向的Person对象在整个程序结束之前是一直占用内存的,如果p和a、b一样是mian中的局部变量,那么在return之前p可能就会被释放,如果p被释放那么问题来了,它指向的对象将成为匿名对象,因为对象还在,以后也不能够释放它,除非程序退出。

三、OC对象中的引用计数器

        OC对象中都有4个字节的空间来存引用放计数器

作用:
        引用计数器表示的是这个对象被引用的次数,alloc、new或者copy出一个新对象,它的引用计数器初值就为1。
一旦它的引用计数器为0,那么系统会毫不留情地回收这个对象,反过来说引用计数器不为0那么它就始终占用内存。于是如你所思,OC的内存管理就是通过平衡引用计数器来完成的,只要保证引用计数器在对象过期时成为0,那么在程序运行过程中就能动态释放过期对象,而避免内存泄露。但是,就小桥看来,保持对象引用计数器的平衡这几个字远没有表面看上去那么简单。
        对单个独立的对象来说,计数器加1减1是清楚明白的,但是当对象与对象之间联系起来的时候,彼此计数器什么时候加1什么时候减1就变得复杂了。 
 操作:
         每个对象有三个继承自根类的方法与内存管理相关。
retain: 发送rratin消息给对象,将对象的引用计数器加1 ,返回值为对象本身;
release:发送release消息给对象,将对象的引用计数器减1,没有返回值;
retainCount:获得对象当前引用计数器的值; 
        前两个就是维持OC对象引用计数器平衡的方法了,管理内存就是通过合适地调用这两个方法,使得对象能在过期时被系统回收,而不是等到程序退出才被回收,如果程序从手机开机就一直运行,那过期对象不就一直占用内存么? 

四、内存管理相关的几个概念
        僵尸对象已经被系统回收的对象叫作僵尸对象,不能再访问。看一下小桥取消ARC并打开Xcode的僵尸对象管理后的测试:

 野指针: 指向僵尸对象或者不能访问的内存的指针叫做野指针,比如上图中的p就是一个野指针,用野指针调用方法就会出上图中的错。
空指针: p = nil;或者 p =NULL;或者p = 0;这三个都是空指针,和野指针相反,在OC中用空指针调用方法是不会报错的。
五、对象遗言 
        最后小桥再复习一下对象被回收前系统给对象发送的消息,这也是对象最后的一个动作了------  dealloc 
OC对象在销毁前都要调用这个方法,用以释放自己占用的资源,再调用父类的 dealloc方法,让父类做相同操作,最后完成所有资源的释放。 管理内存时都要重写这个方法,小桥重写下这个方法:

////  文件:Person.m//  项目:博客笔记////  作者:葬花 桥//  日期:14-5-8//  版权:  Copyright (c) 2014年 itcast. All rights reserved.//#import "Person.h"@implementation Person- (void)dealloc{    NSLog(@"调用了dealloc方法!");    [superdealloc];}@end


         



0 0