码迷,mamicode.com
首页 > 其他好文 > 详细

oc 内存管理初级

时间:2015-08-12 01:31:56      阅读:149      评论:0      收藏:0      [点我收藏+]

标签:

?、内存管理的?式

1、内存常见问题

(1)野指针异常:指针操作已经销毁的对象

指针指向某对象,该对象释放后,该指针即为野指针,对其操作造成野指针异常。

原因:过度释放。

(2)内存溢出:超出内存上限

iOS给每个应?程序提供了?定的内存,?于程序的运?。iPhone 3GS内存 30M左右,iPhone 5S 内存80M左右。?旦超出内存上限,程序就会Crash。

2、内存管理的方式

(1)垃圾回收(gc)   |   OC支持 —  OS X开发 支持   |   iOS 不支持

程序员只需要开辟内存空间,不需要?代码显式地释放,系统来判断哪些空间不再被使?,并回收这些内存空间,以便再 次分配。整个回收的过程不需要写任何代码,由系统?动完成垃圾回 收。Java开发中?直使?的就是垃圾回收技术。

(2)MRC (Manual Reference Count)  |  ??引?计数   |   iOS支持

手动操作引用计数,手动调用控制引用计数的方法

内存的开辟和释放都由程序代码进?控制。

(3)ARC (Auto Reference Count)  |  ?动引?计数   |   iOS支持

自动操作引用计数,编译器调用引用计数的方法

iOS 5.0的编译器特性,它 允许?户只开辟空间,不?去释放空间。它不是垃圾回收!它的本质 还是MRC,只是编译器帮程序员默认加了释放的代码。



?、内存管理机制

C语?中:使?malloc和free,进?堆内存的创建和释放。堆内存只 有正在使?和销毁两种状态。 实际开发中,可能会遇到,两个以上的指针使?同?块内存。C语? ?法记录内存使?者的个数。

OC采?引?计数机制管理内存,当?个新的引?指向对象时,引? 计数器就递增,当去掉?个引?时,引?计数就递减。当引?计数到 零时,该对象就将释放占有的资源。

1、引?计数

    (1)引用计数   标记程序运行期间,对象被引用的次数

    (2)通过操作引用计数,控制对象是否被销毁。

    (3)当引用计数应该减为0时,对象自动被销毁,存储空间被回收

2、操作引?计数的?法

alloc\ retain\ copy\ release\ autorelease

    (1)造成引用计数增加

     除了NSString的对象使用copy 其余的对象类型都声明成retain

        +alloc  当前对象 计数  0 -> 1

     Person * p = [[Person alloc] init];

     NSLog(@"%lu", p.retainCount);

        -retain  当前对象  计数 加1

          指针的引用

     新对象与原对象指向相同对象

     [pretain];

     NSLog(@"%lu", p.retainCount);

     Person * p3 = [p2 retain];

     NSLog(@"%lu,%lu,%lu", p.retainCount, p2.retainCount, p3.retainCount);

        -copy  原来的对象计数 不变   新的对象  0 -> 1

          拷贝

     详情见四

    (2)造成引用计数减少

        release  当前对象  立即减1

     // 调用release,实现引用计数-1

     [p release];

     NSLog(@"%lu", p.retainCount);


     [p release];

     NSLog(@"%lu", p.retainCount);


     // 当引用计数应该减为0时,对象被销毁,存储空间被回收(系统完成)

     // person对象被销毁(只是标记删除,并不清空数据),不建议通过指针操作

     // 对象被销毁后,打印引用计数显示结果为1

     [p release];

     NSLog(@"%lu", p.retainCount);   // 应该减为0

        autorelease   当前对象  延迟减1  非立即

    [pe1 autorelease]; // 未来的某个时刻引用计数-1(管理其的自动释放池release时)

        autoreleasepool的使?:

第一种写法:将对象写在pool的创建和release之间

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

        Person * p = [[Person alloc] init]; // 1

        [p retain]; // 2

        [p retain]; // 3
       
NSLog(@"%lu", pool.retainCount);

        [p autorelease]; // 3

        [p autorelease]; // 3

        NSLog(@"%lu", pool.retainCount);

        // release销毁自动释放池(扔掉垃圾桶)

        [pool release];

        // drain清空自动释放池(只倒垃圾)

        //[pool drain];

第二种写法:mrc支持两种,arc只支持第二种

        Person * pe = [[Person alloc] init];      //1

        [pe retain];     // 2

        NSLog(@"--- %lu", pe.retainCount);     

        @autoreleasepool {

            [pe autorelease];     // 2

            NSLog(@"--- %lu", pe.retainCount);

        }

        NSLog(@"--- %lu", pe.retainCount);     // 1

3、销毁对象

    dealloc  引用计数将要减为0时,对象自动调用

         (1)继承自NSObject,可以不实现,编译器默认实现

         (2)如果实现dealloc方法

             - (void)dealloc

             {

                 代码

                 [super dealloc];    

             }

QA:

dealloc和release到底执行了什么操作?



三、内存管理的基本原则

引?计数的增加和减少相等,当引?计数降为0之后,不应该再使?这块内存空间。

正常情况

     凡是使?了alloc、retain或者copy让内存的引?计数增加了,就需 要使?release或者autorelease让内存的引?计数减少。在?段代码 内,增加和减少的次数要相等

异常情况:

假设当前pe指向的对象的引用计数为1

如果不写[pe release]; main函数运行结束后,局部变量pe被销毁,没有指针指向对象,造成内存泄漏

如果写了不止一句[pe release];造成过度释放。本质:野指针异常(pe 操作已释放的对象)。



四、掌握copy的实现

自定义对象的拷贝要实现NSCopying协议和NSMutablecopying协议,但是在NSCopying协议中也能实现本质上的深拷贝所以只需实现一个方法就可以。

1、深浅拷贝

深拷贝 拷贝的是对象,即创建了新的对象

浅拷贝  拷贝的是指针,即操作的是原来的对象,没有创建新的对象

// 实现浅拷贝
- (
id)copyWithZone:(NSZone *)zone
{
   
return [self retain];

}


// 深拷贝
- (
id)copyWithZone:(NSZone *)zone
{
//    Person * p = [[Person allocWithZone:zone] init];  // 以前的iOS版本需要这样写,如果需要向下兼容可以写这句代码
   
Person * p = [[Person alloc] init];
    p.
name = self.name; // self表示调用copy方法的对象。即被拷贝的对象
   
return p;

}


2、copy mutableCopy

 对象调用copy方法得到的是不可变的对象

 对象调用mutableCopy得到的是可变的对象

 不可变对象创建不可变对象为浅copy其余全为深copy

Xcode打开僵尸对象:

NSString * str1 = @"易荟云";请问str1的retainCount是多少?

@""在常量区,str1的retainCount为最大值。

drain与release区别

在MRC下,两者基本一样,在GC环境下,release 是一个no-op(无效操 作),所以无论是不是gc都使用drain

iOS有没有垃圾回收?autorelease 和垃圾回收制(gc)有什么关系? 

没有。autorelease只是延迟释放,gc是每隔一段时间询问程序,看是否有无指针指向的对象,若有,就将它回收。他们两者没有什么关系。 


oc 内存管理初级

标签:

原文地址:http://my.oschina.net/zooyf/blog/490971

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!