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;
  • 相关阅读:
    idea设置全局ignore
    win 2012 安装mysql 5.7.20 及报错 This application requires Visual Studio 2013 Redistributable. Please ins
    win 2012 安装mysql 5.7.20 及报错 This application requires Visual Studio 2013 Redistr
    kafka 删除 topic
    java编译中出现了Exception in thread “main" java.lang.UnsupportedClassVersionError
    Centos中使用yum安装java时,没有jps的问题的解决
    Spring 整合Junit
    Spring纯注解配置
    Spring 基于注解的 IOC 配置
    打印java系统的信息
  • 原文地址:https://www.cnblogs.com/jianglan/p/4154115.html
Copyright © 2011-2022 走看看