iOS开发中的内存管理机制浅谈

jopen 8年前

iOS开发中的有关内存管理

一、前引

随着移动设备的内存越来越大,程序员也已经度过了为了那一两M的内存在系统的抽丝剥茧的年代,对于JAVA的开发者,对内存更是伸手即取,并且从不关心什么时候还回去。但是,程序的掌控度对程序员来说是至关重要的,任何语言的内存管理机制的初衷也是在有限的空间里完成最精致的逻辑。

二、Xcode工程设置ARC

ARC是xcode5中引入的自动引用计数,其原理与MRC是一样,只是系统帮助我们添加了retain和release。现在在xcode中新建的项目默认都是ARC的环境,我们可以通过设置其为MRC。

在BuildSettings中搜索ARC:


将下面的参数设置为NO,默认是YES。


这时项目工程的环境就变成了MRC。

三、项目中实现MRC和ARC混编

现实中的许多旧的项目,还有一些比较老的第三方库,可能都是采用MRC环境编写的,我们在对其进行扩展或者做新项目的兼容的时候,可以在xcode中对其进行混编。

选择:target->build phases->compile sources


如果工程是ARC,要混编MRC的文件,我们选中compiler flags,后面设置为-fno-objc-arc

如果工程是MRC,要混编ARC文件,我们在后面设置-fobjc-arc

四、IOS内存管理机制基本原理

无论你是只注重于代码逻辑,将内存交给ARC的新时代程序员,还是依然对apple的信任不足,依然事必躬亲的MRC古板程序员,我想你都应该了解IOS中内存管理的机制,尽管ARC机制很成熟也很可靠,可是依然会有很多应用存在循环应用,内存泄露等问题,要知道,ARC不是万能的,它仅仅只是帮你省去写一些繁琐的代码。

首先,在Object-C中创建对象返回的并不是对象本身,而是一个指针。比如我们使用alloc申请空间,会经常这样做:

UIImage * image = [[UIImage alloc]init];

这里,调用的alloc时,系统将给我们创建的类分配一块内存空间,并返回一个指向这个空间的指针。调用init时对对象进行初始化。如果此时,我们将image这个指针置为nil:image=nil;那样将造成内存泄露,系统分配给image的空间永远无法回收。所以,在我们不需要image这个对象时,我们会使用dealloc方法将其交还给系统:[image dealloc];然而这里,有将产生一个严重的问题,如果我们此时打印image的指针,会发现它现在成了一个危险东西,因为它指向的东西不存在了,而它却依然指向那个地方,这便是很多程序员的噩梦:野指针。为此,我们应该养成一个好习惯,不用的指针置为nil,所有对空指针进行的操作都被认为是安全的。

通过上面的理解,我们发现了一个非常麻烦的地方,我申请了一块内存空间,如果我将指针置空了而没有释放对象,则会内存泄露,如果我提前释放了对象,又很可能会有野指针的出现。并且如果有很多类都引用了这个对象,我甚至的不知道我应该什么时候释放它。因此,Object-C为我们引入了引用计数这种管理内存的方法,任何引用这个对象的地方,都应该让这个对象的引用计数加1。同样,任何不再需要这个对象的地方,也应该使它的引用计数减1,如此一来,对象内存便被统一的管理了起来。

五、内存管理的黄金法则

引用计数内存管理的机制是对象的计数,每个对象至少会有一个引用者,如果没有了引用者,对象会被释放。

黄金法则:

1、当你使用alloc,new,copy,mutableCopy创建对象时,你才需要管理他们。

2、你可以使用retain给一个对象增加引用计数。

3、当你不再需要一个对象时,你必须调用release减少其引用计数。

4、你不能释放不属于你的对象的所有权。

上面就是黄金法则的所有内容,我译的可能不到位,总结为一点,也是至关重要的一点就是:谁创建了对象,谁释放掉对象。谁增加了引用计数,谁就在不用时减少计数。alloc,new,copy,mutableCopy,retain这些方法会使引用计数增加,release会使引用计数减少,当计数为0时,系统会调用dealloc释放内存。

六、自动释放池

为了方便内存管理,避免我们频繁的调用release方法,Object-C中还为我们引用了一种机制:自动释放池。自动释放池的原理其实只是延时释放,它并没有帮我们做太多的工作。自动释放池的使用方式有两种:

1、MRC时:

?

1
2
3
     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc]init]; //创建一个自动释放池,系统默认会为我们创建一个,我们也可以创建自己的。
     UIImage * image = [[[UIImage alloc]init] autorelease]; //在池内创建一些对象,会和最近的自动释放池匹配
     [pool release]; //这时自动释放池会向池子中的每一个对象发送release消息

2、ARC时:

?

1
2
3
   @autoreleasepool {
         UIImage * image = [[[UIImage alloc]init] autorelease];
     }



来自: http://my.oschina.net/iOSBoyJack/blog/603504