黑马程序员----oc加强笔记----内存管理

来源:互联网 发布:ug8.0编程在线视频观看 编辑:程序博客网 时间:2024/05/21 06:56

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

1、内存管理基本概念

              为什么要进行内存管理?

                      由于移动设备的内存极其有限,所以每个APP所占的内存也是有限制的,当app所占用的内存较多时,系统就会发出内存警告,个app可用的内存是被限制的,如果一个app使用的内存超过20M,则系统会向该app发送Memory Warning消息。收到此消息后,需要回收一些不需要再继续使用的内存空间,比如回收一些不再使用的对象和变量等,否则程序会崩溃。 

               内存管理范围:

                      管理任何继承NSObject的对象,对其他的基本数据类型无效

                     本质原因是因为对象和其他数据类型在系统中的存储空间不一样,其它局部变量主要存放于栈中,而对象存储于堆中,当代码块结束时这个代码块中涉及的所有局部变量会被回收,指向对象的指针也被回收,此时对象已经没有指针指向,但依然存在于内存中,造成内存泄露。 

2、内存管理的原理

               1)对象的所有权及引用计数 

                           所有权概念:

                                          任何对象都可能拥有一个或多个所有者。只要一个对象至少还拥有一个所有者,它就会继续存在          

                               引用计数器:

                                        每个OC对象都有自己的引用计数器,是一个整数表示对象被引用的次数,即现在有多少东西在使用这个对象。对象刚被创建时,默认计数器值为1,当计数器的值变为0时,则对象销毁。 

                2)对引用计数器的操作 

                                 给对象发送消息,进行相应的计数器操作。retain消息:使计数器+1,该方法返回对象本身release消息:使计数器-1(并不代表释放对象)retainCount消息:获得对象当前的引用计数器值 

               3)对象的销毁

                             当一个对象的引用计数器为0时,那么它将被销毁,其占用的内存被系统回收。当对象被销毁时,系统会自动向对象发送一条dealloc消息,一般会重写dealloc方法,在这里释放相关的资源,dealloc就像是对象的“临终遗言”。一旦重写了dealloc方法就必须调用[super dealloc],并且放在代码块的最后调用(不能直接调用dealloc方法)。一旦对象被回收了,那么他所占据的存储空间就不再可用,坚持使用会导致程序崩溃(野指针错误)。

 注意;

          1) 如果对象的计数器不为0,那么在整个程序运行过程,它占用的内存就不可能被回收(除非整个程序已经退出)

分区 第一天(@传智如意大师) 的第10

非整个程序已经退出 )
         2)
任何一个对象,刚生下来的时候,引用计数器都为1。(对象一旦创建好,默认引用计数器就是3)当使用allocnew或者copy创建一个对象时,对象的引用计数器默认就是1 

3、内存管理分类:

               1)MRC   手动内存管理

                   2)ARC   自动内存管理

4、手动内存管理入门

            代码及理解:

Person类的创建,声明部分:

#import <Foundation/Foundation.h>@interface Person : NSObject@end

Person类的实现部分:

#import "Person.h"@implementation Person//dealloc方法,是对象的临终遗言的方法//对象被销毁的时候,会默认的调用该方法//注意:dealloc 方法是系统根据引用计数器的值,自动调用的,//不需要手动调用- (void)dealloc{    //1 先释放子类自己的对象的空间    NSLog(@"Person已经挂了");    //2 再释放父类的    [super dealloc];}@end
主程序:
#import <Foundation/Foundation.h>#import "Person.h"int main(int argc, const char * argv[]) {    @autoreleasepool {                //用Person 类实例化一个实例对象        Person *p = [Person new];  // 对象有没有所有者?  有//        [p dealloc];        //证明有一个所有者        NSUInteger count = [p retainCount];                NSLog(@"count = %lu",count);  // 1                //使用引用计数器+1//        Person *p2 = p;            //        //Person *p2 = [p retain];        [p retain];        NSLog(@"p.retainCount = %lu",[p retainCount]);   //2                //如果要回收对象?  应该想办法 retatinCount = 0        [p release];        NSLog(@"p.retainCount = %lu",[p retainCount]);   //1                [p release];  //此处执行后,p的空间被回收             //0                //证明p的空间被释放了,可以在在Person类中,重写dealloc方法    }    return 0;}
5、内存管理的原则

            1)原则

                        只要还有人在使用某个对象,那么这个对象就不会被回收;只要你想使用这个对象,那么就应该让这个对象的引用计数器+1;当你不想使用这个对象时,应该让对象的引用计数器-1;

             2)谁创建,谁release

                     (1)如果你通过alloc,new,copy来创建了一个对象,那么你就必须调用release或者autorelease方法
                     (
2)不是你创建的就不用你去负责

            3)谁retain,谁release

                     只要你调用了retain,无论这个对象时如何生成的,你都要调用release

            4)总结

                   有始有终,有加就应该有减。曾经让某个对象计数器加1,就应该让其在最后-1. 

6、单个对象内存管理(野指针问题)

           代码及理解:

创建一个狗的类,声明部分:

#import <Foundation/Foundation.h>@interface Dog : NSObject{    @public    int _a;}-(void)eat;@end
狗类的实现部分:

#import "Dog.h"@implementation Dog-(void)eat{    NSLog(@"狗正在吃一坨粑粑");}- (void)dealloc{    NSLog(@"狗已经挂了");    [super dealloc];}@end
主代码及理解注释:

#import <Foundation/Foundation.h>#import "Dog.h"int main(int argc, const char * argv[]) {    @autoreleasepool {            //创建一个对象        //对象创建完成以后,默认的所有者有一个,是自己,所以引用计数为1        Dog *byd = [Dog new];  //1        [byd eat];  //        NSLog(@"byd.retainCount = %lu",byd.retainCount);        //如果一个对象已经被释放了,这个对象就称之为僵尸对象        //        [byd release];         //0//        NSLog(@"byd.retainCount = %lu",byd.retainCount);  //值已经没有意义了        //这句话默认情况下不报错,        //如果要让他报错,要开启僵尸对象检测        //byd指针也就是野指针//        [byd eat];   //野指针访问        //        [byd retain];  //byd 已经是僵尸对象了,不能复生            }    return 0;}
7、单对象内存管理(内存泄露问题)

代码及理解注释:

创建一个狗的类:

#import <Foundation/Foundation.h>@interface Dog : NSObject-(void)eat;-(BOOL)compareColorWithOther:(Dog*)dog;@end

#import "Dog.h"@implementation Dog-(BOOL)compareColorWithOther:(Dog*)dog{    [dog retain];  //让传入的对象的引用+1        return YES;}-(void)eat{    NSLog(@"狗在吃");}- (void)dealloc{    NSLog(@"狗已经挂了");    [super dealloc];}@end
类存泄露情况总结:
int main(int argc, const char * argv[]) {    @autoreleasepool {                //单个对象的内存泄露问题        //内存泄露情况1:        // 创建完成 使用之后,没有release//        Dog *d = [[Dog alloc] init];  //1//        NSLog(@"%lu",d.retainCount);  //使用d对象               //内存泄露情况2:        //没有遵守内存管理的原则//         Dog *d = [[Dog alloc] init];   //1//         [d retain];  //2////        [d release];//         [d release]; //1                //内存泄露的情况3:        //不当的使用了nil//        Dog *d = [[Dog alloc] init];   //1//        d = nil;//        //        [d eat];  //nil eat//        [d release]; // nil release                //内存泄露的情况4:        //在方法中对传入的对象进行了retain        Dog *d = [[Dog alloc] init];  //1        NSLog(@"d.retainCount = %lu",d.retainCount);        //对象依然被泄露了        [d compareColorWithOther:d];  //2        NSLog(@"d.retainCount = %lu",d.retainCount);                [d release];                    }    return 0;}






 




0 0
原创粉丝点击