A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 周翔 中级黑马   /  2015-12-9 17:24  /  620 人查看  /  0 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

一 、基本原理
Objective-c的内存管理机制与.Net/java那种全自动的垃圾回收机制是不同的,它本质上还是C语言的手动管理方式,只不过稍微加了些自动方法。
1、 Objective-c的对象生成之后,需要一个指针来指向它。
ClassA *class1 = [[ClassA alloc] init];
2、objective-c的对象在使用完成之后不会自动销毁,需要执行dealloc来释放空间(销毁),否则内存泄露。
[class1 dealloc];
这带来一个问题,下面代码中class2是否需要调用dealloc?
ClassA *class1 = [[ClassA alloc] init];
ClassA *class2 = class1;
[class1 hello];//输出hello
[class1 dealloc];
[class2 hello];//能够执行这一行和下一行吗?
[class2 dealloc];
不能,因为class1和class2 只是指针,它们指向同一个对象,[class1 dealloc]已经销毁这个对象了,不能再调用[class2 hello]和[class2 dealloc]. class2 实际上是个无效指针。
3、Objective-c采用了引用计数(ref count或者retain count).对象的内部保存一个数字,表示被引用的次数。例如,某个对象被两个指针所指向(引用)那么它的retain count为2.需要销毁对象的时候,不直接调用dealloc,而是调用release.release会让retain count减一,只有 retain count等于0,系统才会调用dealloc真正销毁这个对象。
ClassA *class1 = [[ClassA alloc] init];//对象生成时,retain count = 1;
[class1 release];//release使retain count减1,retain count = 0,dealloc自动被调用,对象被销毁
我们回头看看刚刚那个无效指针的问题,把dealloc改成release解决了吗?
ClassA *class1 = [[ClassA alloc] init];//retain count = 1
ClassA *class2 = class1;//retain count = 1
[class1 hello];//输入hello
[class1 release];//retain count = 0,对象被销毁
[class2 hello];
[class2 release];
[class1 release]之后,class2依然是个无效指针。问题依然没有解决。

4、 Objective-c指针赋值时,retain count 不会自动增加, 需要手动 retain.
ClassA *class1 = [[ClassA alloc] init];//retain count = 1;
ClassA *class2 = class1;//retain count = 1;
[class2 retain];//retain count = 2
[class1 hello];// 输出hello
[class1 release];//retain count = 2 - 1 = 1
[class2 hello];输出hello
[class2 release];retain count = 0,对象被销毁
问题解决!注意,如果没有调用[class2 release],这个对象的retain count 始终为1,不会被销毁,内存泄露。
这样的确不会内存泄露,但似乎有点麻烦,有没有简单点的方法?
5、Objective-c中引入了autorelease pool(自动释放对象池),在遵守一些规则的情况下,可以自动释放对象。
(autorelease pool依然不是.Net/java那种全自动的垃圾回收机制)
5.1、新生成的对象,只要调用autorelease就行了,无需调用release!
5.2  对于存在指针赋值的情况,代码与前面类似。
      ClassA *class1 = [[[ClassA alloc] init] autorelease];//retain count = 1
      ClassA *class2 = class1;//retain count = 1;
      [class2 retain];//retain count = 2
      [class1 hello];//输出hello
      //对于 class1,无需调用(实际上不能调用)release
     [class2 hello];//输出hello
     [class2 release];//retain count = 2 - 1 = 1
     
6   autorelease pool原理剖析。
6.1  autorelease pool不是天生的,需要手动创立。只不过在新建一个iphone 项目时,xcode会自动帮你写好。autorelease pool的真名是NSAutoreleasePool.
6.2   NSAutoreleasePool 内部包含一个数组( NSMutableArray), 用来保存声明为autorelease的所有对象。如果一个对象声明为autorelease,系统所做的工作就是把这个对象加入到这个数组中去。
     ClassA *class1 = [[[ClassA alloc] init] autorelease];//retain count = 1,把此对象加入autorelease pool中
6.3 NSAutoreleasePool 自身在销毁的时候,会遍历一遍这个数组,release  数组中的每个成员。如果此时数组中成员的retain count为1,那么release之后,retain count为0,对象正式被销毁。如果此时数组中成员的 retain count  大于1,那么 release之后,retain count大于0,此对象依然没有被销毁,内存泄露。
6.4 默认只有一个autorelease pool,通常类似于下面这个例子。
      int main (int argc, const char *argv[])
{

NSAutoreleasePool *pool;

pool = [[NSAutoreleasePool alloc] init];



// do something



[pool release];

return (0);

}

     所有标记为autorelease 的对象都只有在这个pool销毁时才被销毁。如果你有大量的对象标记为autorelease, 这显然不能很好的利用内存,在iphone这种内存受限的程序中很容易造成内存不足的。
int main(int agrc,char *argv[])
{

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    int i,j;

    for (i = 0; i < 100; i++)

    {

        for (j = 0; j < 10000; j++)

        {

            [NSString stringWithFormat:@"1234567890"];//

        }

    }

    [pool release];

    return 0;

}

运行时通过监控工具可以发现使用的内存在急剧增加,直到pool 销毁时才被释放。

Objective-c程序中可以嵌套创建多个autorelease pool.在需要大量创建局部变量的时候,可以创建内嵌的autorelease pool 来及时释放内存。


int main(int agrc,char *argv[])

{

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    int i,j;

    for (i = 0; i < 100; i++)

    {

        NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];

        for (j = 0; j < 10000; j++)

        {

            [NSString stringWithFormat:@"1234567890"];//

        }

        [loopPool release];

    }

    [pool release];

    return 0;

}

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马