zoukankan      html  css  js  c++  java
  • 【object-c 学习笔记】第9章 内存管理

    1、概念理解

    举例:以图书馆为例,如果每个人都只借不还,那么图书馆最终将会因无书可借而倒闭。

    概念:当程序运行结束时,操作系统将收回占用的资源,但是只要程序还在运行,它会一直占用资源,如果不进行清理,某些资源将被耗尽,程序有可能会崩溃,内存管理就是确保在需要的时候分配内存,不需要使用的时候释放内存

    2、对象生命周期

      包含诞生(通过alloc或者new方法实现)、生存(接受信息并执行操作)、交友(通过复合以及向方法传递参数)、以及死去(释放内存)。

    3、引用计数

      cocoa采用引用计数了解对象的生命周期是否结束了。

    (1)计数方法

     a.计数器值加1,表示某段代码需要访问一个对象;

     b.计数器值减1,表示某段代码结束访问一个对象;

     c.计数器值为0,表示不再有代码访问该对象了,因此它将销毁,其占用的内存被系统回收以便重用。

     (2)使用方法

     a. 当计数器值为0时,object-c会自动向对象发送一条dealloc消息;可以重写dealloc方法,把已经分配的全部相关资源释放。

       注意:一定不要直接调用dealloc方法,,object-c会自动销毁对象时自动调用它。

     b.当需要获得引用计数器当前的值,可以发送retainCount消息。

    //retain、release、retainCount的方法申明
    1 -(id)retain;
    2 - (oneway void) release;
    3 - (NSUInteger) retainCount;
      retain方法返回一个id类型的值,通过这种方式,可以在接受其他消息的同时进行retain调用,增加对象的保留计数器的值和傲气对象完成某种操作。例如:
    [[car retain]setTire:atIndex:2]; 表示要求car对象将其保留计数器的值加1并执行setTire操作。

    (3)案例
    a.创建一个RetainTracker类的对象,该对象在初始化和销毁时调用了NSLog()函数,当对象的保留计数器的值归0时,将自动发送dealloc消息,例子中,init和dealloc这两个方法使用NSLog()输出一条信息,表明他们被调用了。
     1 @interface RetainTracker : NSObject
     2 @end//RetainTracker
     3 
     4 @implemetation RetainTracker
     5 -(id) init
     6 {
     7    if (self = [super init])
     8    { 
     9        NSLog(@"init : Reetain count of %d." , [self retainCount]);
    10    }
    11    return(self);
    12 }//init
    13 
    14 -(void)dealloc
    15 {
    16    NSLog(@"dealloc called. Bye Bye.");
    17    [super dealloc];
    18 }//dealloc
    19 @end//RetainTracker

      在main()函数中创建了一个新的RetainTracker类的对象,并间接调用了由Retain-Tracker类定义的两个方法。当一个新的RetainTracker类的对象创建完毕后,就会向它发送retain消息或release消息,以增加和减少对象的保留计数器的值,以下是NSLog()函数有趣的输出结果。

     1 int  main(int argc,const char  *argv[])
     2 {
     3    RetainTracker *tracker = [RetainTracker new]; //count:1
     4 
     5    [tracker retain];  //count:2
     6    NSLog(@"%d",[tracker retainCount]);
     7 
     8  
     9    [tracker retain];  //count:3
    10    NSLog(@"%d",[tracker retainCount]);
    11 
    12    [tracker release];  //count:2
    13    NSLog(@"%d",[tracker retainCount]);
    14 
    15    [tracker release];  //count:1
    16    NSLog(@"%d",[tracker retainCount]);
    17 
    18    [tracker retain];  //count:2
    19    NSLog(@"%d",[tracker retainCount]);
    20 
    21   [tracker release];  //count:1
    22    NSLog(@"%d",[tracker retainCount]);
    23 
    24   [tracker release];  //count:1
    25    return(0);
    26 }//main

    运行后结论:

    -------------------------------------------------------------------------------------------------------------------------------------------

    init Retain count of 1.

    2

    3

    2

    1

    2

    1

    dealloc called. Bye Bye.

    -------------------------------------------------------------------------------------------------------------------------------------------

    4、对象所有权

      回忆下,car类的变量engine的存取方法:

    1 //car类的变量engine的存取方法
    2 -(void) setEngine : (Engine *) newEngine;
    3 
    4 //在main()函数中调用该方法:
    5 Engine *engine = [Engine new];
    6 [car setEngine : engine];

      那么那个实体拥有engine对象?

      car类正在使用engine底线,所以不可能是main()函数;main()随后可能会使用engine对象,也不可能是car的;解决办法是car类保存engine对象,将engine对象的保留计数器的值增加到2.

    5、访问方法中的保留和释放

      setEngine方法的第一个内存管理版本

    1 -(void)setEngine : (Engine *)newEngine
    2 {
    3    [newEngine retain];
    4    [engine release];
    5    engine = [newEngine retain];
    6 }//setEngine
    7 //首先保留新的engine对象,即使newEngine和engine是同一个对象,保留计数器的值也会先增加,然后立即减少,由于没有归0,engine对象也没被销毁,就不会引发错误了。
    8 //假设先保留新对象,在释放对象就会出问题。

    6、自动释放

      description方法的例子(该方法返回一个用来描述对象信息NSString类型值)

     1 -(NSString *) descrinption
     2 {
     3    NSString *description;
     4    description = [[NSString alloc] initWithFormat: @"I am %d years old",4];
     5 
     6    return(description);
     7 }//description
     8 //使用alloc 方法创建一个新的字符串实例(alloc方法将该对象的保留计数器的值设置为1),然后返回该字符串实例。
     9 //调用description方法的代码将返回的字符串赋在某个变量中,并在使用完毕后将其释放
    10 NSString *desc = [someObject description];
    11 NSLog(@"%@",desc);
    12 [desc release];

    7、所有对象放入池中

      Cocoa中有一个自动释放池(autorelease pool)概念:用来存储对象的集合,并且能够自动释放。

      NSObject类提供一个叫autorelease的方法:

      -(id)autorelease;

      该方法预先设定了一条在未来某个时间发送的release消息,其返回是接收这条信息的对象,当给一个对象发送autorelease消息时,实际上是该对象添加到了自动释放池中,当自动释放池被销毁是,会像该池中的所以对象发送release消息。

    -(id)autorelease;
    
    -(NSString *) descrinption
    {
        NSString *description;
        description = [[NSString alloc] initWithFormat: @"I am %d years old",4];
     
        return(description);
     }//description
    
    NSLog(@"%@", [description autorelease] );
    //因为description方法首先创建了一个新的字符串对象,然后自动释放该对象最好将其返回给NSLog()函数,所以内存管理问题解决了。由于description方法中的字符串对象是自动释放的,该对象暂时被放入了当前活动的自动释放池中,等到调用NSLog()函数的代码结束后,自动释放池会被自动销毁。

    8、自动释放池的销毁时间

      介绍2种方法创建一个自动释放池

      1、通过@autoreleaspool关键字

      2、通过NSAutoreleasepool对象

      

      在Foundation库工具集中,创建和销毁自动释放池由@autorelease关键字完成。当你使用@autorelease{}时,所有在花括号里的代码都会被放入这个新的池子中,如果你的程序是密集型的可以使用这种自动释放池。

      注意:任何在花括号里定义的变量在括号外都无法使用;使用NSAutoleasePool对象,如果你使用了这个方法,创建和释放NSAutoreleasePool对象之间的代码就会使用这个新的池子。

    NSAutoreleasePool *pool;
    pool = [NSAutoreleasePool new];
    ~
    [pool release];
    //创建一个自动释放池后,该池子就会成为活动的池子,释放该池后,其保留计数器的值归0,然后该池被销毁,销毁过程中,该池将释放其包含的所有对象

    9、自动释放池的工作流程

     1 int main(int argc , const char *argv[])
     2 {
     3 //创建自动释放池
     4    NSAutoreleasePool *pool;
     5    pool = [[NSAutoreleasePool alloc] init ];
     6    
     7 //每次向某对象发送autorelease消息,该对象会被添加到自动释放池中
     8    RetainTracker *tracker;
     9    tracker = [[RetainTracker new]];//count:1
    10 
    11 //创建一个新的tracker对象,因为创建时接收了一条new消息,所以保留计数器值为1,接下来保留该对象,保留计数器增加到2
    12    [tracker retain];//count:2
    13 //该对象被自动释放,但其保留计数器值仍然不变;
    14    [tracker autorelease]; //count:still 2
    15 //注意我们之前创建的自动释放池中现有一个引用指向该对象,当自动释放池被销毁时,将tracker对象发送一条release消息
    16    [tracker release];//count:1
    17 //之后释放该对象以抵消之前对他执行的保留操作,该对象的保留计数器值仍大于0,所以处于激活状态
    18    NSLog(@"releasing pool");
    19    [pool release];
    20 
    21    @autoreleasepool
    22    {
    23        RetainTracker *tracker2;
    24        tracker2 = [RetainTracker new]; //count:1
    25        [tracker2 retain];//count:2
    26        [tracker2 autorelease]; //count:still 2
    27        [tracker2 release];//count:1
    28 
    29        NSLog(@"auto releasing pool");
    30    }
    31 
    32    return(0);
    33 }//main
  • 相关阅读:
    备战noip week1
    20200820校测
    UVA 11419 SAM I AM
    需求沟通技巧
    ReentrantLock和ReentrantReadWriteLock对比
    线程池浅析
    常用设计模式之单例模式
    java开发3~5年工作经验面试题
    2019计划
    Linux系统安装Tomcat
  • 原文地址:https://www.cnblogs.com/sallyWei/p/4498843.html
Copyright © 2011-2022 走看看