zoukankan      html  css  js  c++  java
  • 《objective-c基础教程》学习笔记(十)—— 内存管理

      本篇博文,将给大家介绍下再Objective-C中如何使用内存管理。一个程序运行的时候,如果不及时的释放没有用的空间内存。那么,程序会越来越臃肿,内存占用量会不断升高。我们在使用的时候,就会感觉很卡,最终使得程序运行奔溃。因此,将无效的内存及时清理释放,是非常有必要的。

      一个对象在最初创建使用,到最后的回收释放,经历的是怎样一个过程呢?
    包括:诞生(通过alloc或new方法实现)、生存(接收消息并执行操作)、交友(通过复合以及向方法传递参数)、最终死去(被释放掉)。


    一、引用计数

      在对象创建的时候,Cocoa使用了一种叫引用计数的技术:
    1)当一个对象被访问的时候,引用计数器的值就加1,可以给对象发送一条retain消息
    2)当结束该对象的访问的时候,引用计数器的值就减1,可以给对象发送一条release消息
    3)当引用计数器的值为0的时候,表示不再访问该对象,则其占用的系统内存将被回收重用,会自动给对象发送一条dealloc消息,一般都会重写dealloc方法;
    4)要获得保留计数器当前的值,可以发送retainCount消息

      下面,介绍下几种方法的声明和实现方法:

    首先,新建一个RetainTracker的类,修改类的声明文件和实现方法:

    1 // RetainTracker.h
    2 
    3 #import <Foundation/Foundation.h>
    4 
    5 @interface RetainTracker : NSObject
    6     -(id) retain;
    7     -(oneway void)release;
    8     -(NSUInteger)retainCount;
    9 @end
     1 // RetainTracker.m
     2 
     3 #import "RetainTracker.h"
     4 
     5 @implementation RetainTracker
     6 -(id) init
     7 {
     8     if(self == [super init])
     9     {
    10         NSLog(@"init: Retain count of %lu.", [self retainCount]);
    11     }
    12     return (self);
    13 }
    14 
    15 -(void) dealloc
    16 {
    17     NSLog(@"dealloc called. ByeBye!");
    18     [super dealloc];
    19 }
    20 
    21 @end

    然后在main.m主函数中调用retain,release,retainCount,dealloc等方法:

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

    运行结果如下:

    二、自动释放

      大家都知道,当对象不再使用的时候,要及时释放。但是在某些情况下,弄清楚什么时候不再使用一个对象并不容易。如果能够自动释放就好了。很幸运,Cocoa中有一个自动释放池(autorelease pool)。细心的朋友可以发现,在ios5以后,每次新建项目,在main函数中都有个@autoreleasepool方法,这就是将执行的代码都加到自动释放池中。

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

    1 -(id) autorelease;

      该方法预先设定一条会在未来某个时间发送的release消息。当给一个对象发送autorelease消息的时候,实际上是将该对象添加到自动释放池中。当自动释放池被销毁时,会向该池中的所有对象都发送release消息。

      那么,接下来,我们就用添加到自动释放池的方法来修改上面的例子。RetainCount类的内容不改变,只要修改main主函数中的内容:

     1 /* use auto release pool */
     2 int main(int argc, const char * argv[])
     3 {
     4     NSAutoreleasePool *pool;
     5     pool = [[NSAutoreleasePool alloc] init];
     6     
     7     RetainTracker *tracker = [RetainTracker new];// count =1
     8     NSLog(@"after new, tracker: %lu", [tracker retainCount]);// count =1
     9     
    10     [tracker retain];
    11     NSLog(@"after retain, tracker: %lu", [tracker retainCount]);// count =2
    12     [tracker autorelease];
    13     NSLog(@"after autorelease, tracker: %lu", [tracker retainCount]);// count =2
    14     
    15     [tracker release];
    16     NSLog(@"after release, tracker: %lu", [tracker retainCount]);// count =1
    17     NSLog(@"releasing pool");
    18     [pool release]; // 销毁自动释放池
    19     
    20     @autoreleasepool {
    21         RetainTracker *tracker2;
    22         tracker2 = [RetainTracker new]; // count = 1
    23         [tracker2 retain]; //count =2
    24         [tracker2 autorelease]; // count still = 2
    25         [tracker2 release]; //count = 1
    26         NSLog(@"auto releasing pool.");
    27     }
    28     
    29     return (0);
    30 }

      运行结果:

      tracker对象,通过autorelease消息,将该对象添加到自动释放池中。当pool自动释放池发送release消息的时候,pool对象的引用计数器的值为0,则该自动释放池要被销毁,其dealloc方法被调用。使得自动释放池中的对象也都跟随其一起被销毁。

    三、内存管理规则

      接下来,就给大家介绍下Cocoa的内存管理的几个规则。

    1). 当你使用 new, alloc, copy 方法创建一个对象时,该对象保留计数器的值为1;
         当不使用的时候,要发送一条release或autorelease消息,销毁对象。

    1 NSMutableArray *array;
    2 array = [[NSMutableArray alloc] init]; //count =1
    3 //use the array
    4 [array release];//dealloc, count =0

    2). 当你通过别的方法获得一个对象时,假设该对象的保留计数器的值为1,而已经被设置为自动释放,则不需要执行任何操作来清理该对象。

    1 NSMutableArray *array;
    2 array  =  [NSMutableArray arrayWithCapacity:17 ]; //count =1, autorelease;
    3 //use the array

    3). 自动释放池销毁的时间是完全确定的,它在循环阶段是不会被销毁的。如果一个循环要添加到自动释放池中的对象很多的时候,可以考虑循环一部分后先分批释放掉一些,然后再创建新的自动释放池。这样就保证自动释放池的分配和销毁操作代价尽可能的小。

     1 NSAutoreleasePool *pool;
     2 pool = [ [NSAutoreleasePool alloc] init ];
     3 int i;
     4 for(i=0; i<100000; i++)
     5 {
     6     id object = [someArray objectAtIndex: i];
     7     NSString *desc = [object descrption];
     8     If(i%100 == 0)
     9     {
    10         // 每循环一百次就清空一次,然后新建一个自动释放池
    11     [pool release];
    12     pool = [[NSAutoreleaasePool alloc]init];
    13 }
    14 }
    15 [pool release];

    4). 自动引用计数(Auto Reference Counting,即:ARC),如果你启用了ARC,只要像平时一样按需分配并使用对象,编译器会帮你插入retain和release,无需你自己手动添加。ARC只能保留Objective-c的指针对象,即:继承NSObject的对象。

    5). Ios 5 以上,有了归零弱引用,因为在指向的对象释放之后,这些弱引用就会被设置为零(即:nil),然后对象就会像平常指向nil值的指针一样被处理。使用前要先明确声明,声明方法如下:

    1 _weak NSString *myString; 或
    2 @property(weak) NSString *myString;
  • 相关阅读:
    深度学习练习(三)
    深度学习核心技术笔记(一)
    tensorflow的函数
    举例
    Tensorflow 笔记
    tensorflow框架
    基于python的感知机
    深度学习练习(一)
    深度学习练习(二)
    [javascript 实践篇]——那些你不知道的“奇淫巧技”
  • 原文地址:https://www.cnblogs.com/jianglan/p/4154115.html
Copyright © 2011-2022 走看看