iOS开发-内存管理

内存管理

对这篇呢,其实现在犹是ARC模式,正常状态下中心不用我们失去手动释放内存,所以一旦不是若面试呀、装逼或者扎实功底的,就先别看了还是了解下即可,因为像面试时,有些面试官想看您的基本功经常,就不怎么人会问,现在做事为主未会见就此到。

 

攻目标

  1. 控制内存管理之法则

  2. 支配手动内存管理

 

===============================================

1.用懂得的学识

1.1内存管理

1.1.1 C的内存管理,以及劳动的远在

char *p = (char *)malloc(100*sizeof
(char)); 

立刻是C的动态内存分配,我们手动以及系统报名了100独字节的内存;或者说系统以积里开发了100单字节的上空,并以这个空间的首地址返回给指针变量p。

strcpy(p,”Hello World!”);

拿字符串拷贝给指针变量p指向的内存空间。

puts(p);

以p指针指向的内存空间里之字符串打印出来。

free(p);

下形成后,手动与系统放内存空间;或者说系统回收空间。

如齐即是C里大概的内存管理。

C的内存管理,我们手动申请,手动释放。这样来拘禁,我们仅需要小心少独问题即使哼了:

1,申请内存,使用好后待自由,如果无自由会导致内存泄露。

2,不可知数放,如果频繁放,则会倒。

唯独,如果项目比较复杂,需要发出几十森号人共分工到位,就异常易并发问题。

假如说咱们开拓了同等块内存空间,里存了平片很有因此底数。但是,这个数量不只有自身当就无异块代码里之所以,甚至发生多个人,在程序的多只地方用。这样造成的结果虽是,就终于我用完这块内存,我吗不克去放活他,因为自身莫可知确定,别人在别的地方是否还用运用这块内存。内存泄露在所难免了。

 

 

 

 

OC的内存管理:

1.1.2 引用计数(retainCount)

对同动态申请的内存,有一个人(指针)使用,就被这个内存的计数器加1,使用好后,就让此计数器减1,当这内存的援计数为0了,我们重新自由他,这样,上面的问题虽解决了。OC,就是用引用计数这种方法来管理内存的。

 

 

 

1.1.3 内存管理之黄金法则

对引用计数来说,有同仿内存管理的黄金法则:

The basic rule to apply is everything that
increases the reference counter with alloc, [mutable]copy[withZone:]
or retain is in charge of the corresponding [auto]release.

万一对一个目标下了alloc、copy、mutablecopy、retain,new,那么您必下

相应的release或者autorelease。

通俗一点之说法便是孰污染谁治理。

 

 

 

            

1.1.4 objective-C的内存管理遵守下面这简单的国策:

1.你富有你创造的目标,也就是说创建的目标(使用alloc,new,copy或者mutalbeCopy等措施)的启幕引用计数是1。

2.受目标发送retain信息后,你有了这个目标 ,retainCount+1

3.当你莫需要使用该目标时,发送release或者autorelease消息放弃这目标

4.毫无对君无有的对象发送“放弃”的音讯

 

 

 

 

 

1.1.4 MRC和ARC

ARC Automatic Reference
Counting,自动引用计数,由xcode,帮咱失去管理内存。

MRC Manual  Reference
Counting,手动引用计数,我们手动管理内存。

 

Xcode 5.0  版本之后默认是ARC模式,

 

 

 

 

 

 

 

1.1.5 如何以工程变更吗MRC

xcode5,工程创造的时是ARC的,我们只要想只要MRC,需要进行如下设置。

选中工 – target – Bulid Settings
-Automatic Reference Counting改吧NO。

 

 

 

1.1.6 ARC执行了初的规则

 

● 开发者不克亮调用dealloc;不可知兑现和调用retain、release、retainCount和autorelease。

取缔利用@selector(retain),@selector(release)等等。

开发者仍可以兑现dealloc方法,如果你想治本资源使休是变量。

ARC中从定义之dealloc方法,不需调用[super
dealloc](其实这么做就见面促成编译错误),编译器会强制自动链接到父类。

开发者仍可以针对Core
Foundation-style对象,使用CFRetain,CFRelease和其余有关措施。

 


开发者不可知动用NSAutoreleasePool对象。ARC下以@autoreleasepool,它比较NSAtuoreleasePool更有效率。

 

为了配合手动引用计数,ARC的艺术命名有限制:


访问器方法不能够就new开头,反过来就是:开发者不克声称一个曾经new开头的性,除非您于您指定一个getter

 

// 不正确 
@property NSString *newTitle;   

// 正确 
@property (getter=theNewTitle) NSString *newTitle;  

 

 

1.1.7.野指南针错误形式以Xcode中便表现吗:Thread
1:EXC_BAD_ACCESS(code=EXC_I386_GPFLT)
错。因为你拜访了千篇一律片就不属于公的内存。

 

2.欲记住的文化

 

2.1 alloc与release

创建一个Dog类

@interface Dog : NSObject

  @end

  @implementation Dog

  - (void)dealloc

  {

    NSLog(@"dog dealloc");

    [super dealloc];

  }

  @end

 

 
delloc里的析构函数,当目标销毁之下,会活动调用这个主意,我们于此更写是措施。

  在main函数里,写副如下代码:

   

int main(int argc, const char * argv[])

  {

    @autoreleasepool {

        Dog *dog = [[Dog alloc] init];

     }

    NSLog(@"程序即将退出");

    return 0;

  }

 

 
从极限打印信息来拘禁,程序将退出这漫长打印前,已经打印dog
dealloc,也就是说在程序运行结束前,dog对象已经销毁了。这个是ARC,由xcode帮我们管理dog对象。

 
将ARC改吗MRC,再实行顺序,dog对象并没有灭绝,因为我们现凡是手动管理了,我们得遵循内存管理的黄金法则,Dog
*dog = [[Dog alloc] init];
我们要针对dog进行release。将main函数代码改也如下形式:

int main(int argc, const char * argv[])

{

    @autoreleasepool {

        Dog *dog = [[Dog alloc] init];

     [dog release];

     }

    NSLog(@"程序即将退出");

    return 0;

}

 

又实施顺序,从打印好看,dog对象,已经灭绝。这即是金法则,我们针对dog进行alloc,就假设针对性dog进行release。

注意,release
并无是绝迹对象,让对象的援计数减1,当对象的援计数为0的下,自动调用dealloc方法,销毁对象。

 

 

 

2.2 retain与retainCount

retain,将对象进行保存操作,也就算是要是对象的援计数加1。

retainCount,打印一个对象的援计数。

 

 

 

 

 

2.3 类的复合中行使

在点代码中,增加Person类

@interface Person : NSObject {

  // 一个人,养了一条狗(持有一条狗)

    Dog *_dog;

  }

  - (void)setDog:(Dog *)dog;

  - (Dog *)dog;

  @end

  @implementation Person

  /* 版本1 (有问题) 人并没有真正持有狗,如果在main函数里[dog release],让dog的引用计数减1,就变为0,dog就销毁了。

    - (void)setDog:(Dog *)dog

  {

    _dog = dog;

  }

    */



  /* 版本2 (有问题) 如果人再持有别的狗,就会造成第一条狗得不到释放,内存泄露。

  - (void)setDog:(Dog *)dog

  {

    _dog = [dog retain];

  }

    */



  /* 版本3 (有问题) 如果本来持有一条狗,又重新设置这条狗,先进行release,这个时候,很可能dog就销毁了,然后,就没法再次retain了。

  - (void)setDog:(Dog *)dog

  {

    [_dog release];

    _dog = [dog retain];

  }

    */



  // 版本4 OK!,标准写法

  - (void)setDog:(Dog *)dog

  {

    if (_dog != dog) {

         [_dog release];

          _dog = [dog retain];

      }

  }



  - (Dog *)dog

  {

    return _dog;

  }



  - (void)dealloc

  {

    NSLog(@"person dealloc");

  // 人在销毁的时候,一并将持有的dog对象销毁

    [_dog release];

    [super dealloc];

  }

 

 

 

 

//MRC:

黄金法则:

使利用了alloc/retain/copy/mutableCopy,new, 创建了靶

那么尽管得使用release进行自由,

———总结一句话就是是:谁创建,谁背释放

retain   —  使对象的援计数+1,
如果指针需要去有这个目标

需要利用retain

retainCount:  返回对象的援计数值 

release :  — 使对象的援计数 -1,
而非是假释对象

dealloc:对象销毁之早晚(也就是是retainCount为0的当儿)自动调用这个艺术

 

 

 

 

 

MRC:

2.4 @property
retain,assign,copy展开

2.4.1 retain展开

若达到代码里,Person的setter和getter方法,也得就此property,写成如下形式

@property (nonatomic, retain) Dog
*dog;

             则会进展如下:

- (void)setDog:(Dog *)dog

{

  if (_dog != dog)

  {

    [_dog release];

    _dog = [dog retain];

  }

}

 

 

 

2.4.2 assign展开

  //简单数据类型 ,OC的内存管理于简易的数据类型 int\float…, 

   

@property (nonatomic, assign) Dog *dog;,assign是直接赋值,则会展开如下:

- (void)setDog:(QFDog *)dog

{

  _dog = dog;

}

 

 

 

 

 

  2.4.3 copy展开  ,
复制一客原来的目标

 

//copy 多用来字符串

@property (nonatomic, copy)NSString *name;

           展开如下:

- (void)setName:(NSString *)name

{

  if (_name != name)

  {

    [_name release];

    _name = [name copy];

  }

}

 

 

 

 

 

 

 

 

2.4 字符串内存管理

  2.4.1 字符串的内存管理

  // 对于字符串而言,非常勿遵从黄金法则!
(如果从字符串的援计数来拘禁,乱七八糟!) 这就是一个表象!
其实里面或按照的!!

        // 我们设召开的凡,我们照例遵守我们的黄金法则!

       

之所以,如果是NSString,我们的property格式写成如下: @property (nonatomic,
copy) NSString *name;

 

2.4.2 copy和mutableCopy

       

 

 

2.5 数组的内存管理

 

 

 

 

结论

 
1)当我们创建数组的早晚,数组会对每个对象进行引用计数加1

 
2)当数组销毁的时,数组会对每个对象开展引用计数减1

 
3)当我们于数组添加对象的时段,会针对目标进行引用计数加1

 
4)当我们深受数组删除对象的时刻,会针对目标开展引用计数减1

 
总之,谁污染谁治理,管好自己不怕足以了(数组内部也遵循内存管理)。

 

 

 

 

2.6 autorelease与autoreleasepool

在main函数里写如下代码:

int main(int argc, const char * argv[])

  {

    @autoreleasepool {

           Dog *dog = [[Dog alloc] init];

      //dog并没有马上销毁,而是延迟销毁,将dog对象的拥有权交给了autoreleasepool

      [dog autorelease];

      //这个是可以打印的,因为打印完dog的引用计数后,dog对象才销毁

      NSLog(@"retainCount = %lu",dog.retainCount);

     }

    NSLog(@"程序即将退出");

    return 0;

  }

 

 
autoreleasepool相当给一个频组,如果哪个目标发送autorelease消息,实际用对象的有所权交给了autoreleasepool;当autoreleasepool销毁之时光,autoreleasepool里富有的目标还发送一个release消息。

 

2.7 加方的内存管理 

 
我们因此加方创建的对象,不用我们release,是以接近里的贯彻采用了autorelease,延迟释放

  在Dog类的宣示里搭一个加计

  + (id)dog;

  以Dog类的贯彻里展开落实

  + (id)dog

  {

只顾,这里并非写成release,如果是release,那么巧创立就销毁了,使用autorelease,使得用对象的有权交给了机动释放池,只要自动释放池没有灭绝,dog对象为尽管无见面销毁。

return [[[Dog alloc] init]
autorelease];

  }

 

 

2.8  对于自动内存释放简单总结一下:

  1.                1
    autorelease方无会见转目标的援计数器,只是用之目标放置自动释放池中;
  2. 机动释放池实质是当自动释放池销毁后调用对象的release方法,不自然就是会销毁对象(例如如果一个
                对象的援计数器>1则这即使无法销毁);
  3. 鉴于活动释放池最后统一销毁对象,因此一旦一个操作比较占内存(对象比较多或目标占资源比较多),最好不用坐自动释放池或者考虑放到多单自动释放池;
  4. ObjC中类库中的静态方法一般还无欲手动释放,内部都调用了autorelease方法;

 

 

=====================================

 

ARC模式下之要字:

__strong/__weak/__unsafe_unretain

 

开发者需要科学修饰变量。使用下的格式来修饰变量声明。

 

             类名*  修饰  变量名

             例如:

 

       MyClass * __weak myWeakReference;   
       MyClass * __unsafe_unretained myUnsafeReference; 

 

 

对应之@property 参数分别吗

strong/weak/unsafe_unretain

 

__strong :
强引用,相当给MRC下之retain,指对对象具备决定的占用

                           
有,默认情况。

__weak :    
弱引用,指对对象非拥有决定的挤占,相当给MRC下的

     
assign,对象释放后,指针赋值为nil。

__unsafe_unretain:弱引用,指对对象非具决定的占有,相当给MRC下之assign,对象释放后,指针也悬垂指针(不见面赋值为nil),可以会油然而生野指针,不建议采用。

 

@property(nonatomic, strong) xxx

//set 类似于 retain 展开  [name
retain]

@property(nonatomic, weak)  xxx

//类似于 assign

@property(nonatomic, unsafe_unretain)
xxx

//类似于 assign

 

相关文章