iOS内存管理

来源:互联网 发布:唱杀破狼的js是谁 编辑:程序博客网 时间:2024/06/05 05:55

iOS的内存管理,MRC ARC,具体的规则都能了解一些的,知其然,更要知其所以然。

 分享下内存分配的预备知识:

一个由C/C++编译的程序会分为5个部分:栈区,堆区,全局区(静态区),文字常量区,程序代码区。  

其中只有堆区是需要程序员管理的,那么内存管理核心就是堆区内存管理。

iOS Object-C是类C语言,那就先要了解C语言的内存,C语言动态内存分配提供malloc, calloc, realloc, free等函数,从操作系统中获取、使用和释放内存。

由基本的这些函数延伸出来的内存策略大致有:引用计数、内存池、垃圾收集等策略。

iOS采用的策略为引用计数,引用计数是一种半自动的内存管理技术,需要编程支持。

引用计数中,共享数据结构中有一个域来标识"引用"结构的次数,当程序指令中有一个指向此数据结构指针时,该引用计数+1。通俗来讲,它正在被存储在多少个位置上。

对它使用后,引用计数-1,此时检查计数是否为0。(为0,释放内存)。

 引用计数的好处:防止正在使用数据结构是释放该结构。

 引用计数的坏处:难以处理发生循环引用的数据结构。

实现引用计数需要两个函数:增加计数函数,减少计数函数(需判断为0 释放内存);对应iOS增加计数的为alloc,retain 减少计数为release 。

看下代码:

struct obj_layout {
    NSUInteger retained;
};
+ (id) alloc
{
    int size = sizeof(struct obj_layout) + 对象大小;
    struct obj_layout *p = (struct obj_layout *)calloc(1,size);
    return (id)(p+1);
}


- (id) retain
{
    NSIncrementExtraRefCount(self);
    return self;
}
inline void
NSIncrementExtraRefCount (id anObject)
{
    if (((struct obj_layout *)anObject)[-1].retained == UINT_MAX – 1)
        [NSException raise: NSInternalInconsistencyException
            format: @"NSIncrementExtraRefCount() asked to increment too far");
    ((struct obj_layout *)anObject)[-1].retained++;
}

- (void) release
{
    if (NSDecrementExtraRefCountWasZero(self))
        [self dealloc];
}
BOOL
NSDecrementExtraRefCountWasZero (id anObject)
{
    if (((struct obj_layout *)anObject)[-1].retained == 0) {
        return YES;
    } else {
        ((struct obj_layout *)anObject)[-1].retained--;
        return NO;
    }
}

这就是MRC下,alloc/retain 一定对应 release的原理,CFCreatObject 对应CFRelease。

在说下apple牛逼的ARC,自动引用计数,并不是垃圾回收机制,注意iOS编码中的内存管理一定是引用计数,改动只是针对OC对象的,之所以这么做,是因为它还做不到C结构的自动计数,在编译中加了相关的优化而已,替开发者添加相关代码达到内管隐式管理,这就带来了一个比较麻烦的问题,需要区分对待OC和CF对象,当然apple都给你想到了,怎么样在ARC下的内存管理。如下:

1、修饰符,__strong, __weak,__unsafe_unfetained,_autoreleasing。

__strong是缺省的修饰符,在不适用任何修饰符的情况下,默认此修饰符,编译器自动为修饰符修饰的对象生成release代码。

例如:NSString *string = [NSString alloc]init];    等价于NSString  __strong *string = [NSString alloc]init]; 

__weak修饰符修饰的对象,运行时系统会记录该指针,对象释放时,此指针置为nil,最大用处在消除循环引用和避免程序崩溃。

__unsafe_unfetained修饰的对象,在对象释放时,不会将指针置为nil, 之所以有为了支持iOS/OS X。

_autoreleasing修饰符修饰的对象指针注册在自动释放池,id指针(或者对象指针的指针)默认为__autoreleasing  函数参数以及返回值为__autoreleasing

2、ARC规则 

   retain release retainCount autorelease不会再用(包括内部调用的  NSAllocateObject NSDeallocateObject),编译器也不会通过;

  不可以显式调用dealloc,

  用@autoreleasepool{}块代替NSAutoreleasePool;

  对象类型变量不能在C的struct/unin作为成员,

  id void*显示转换,__bridge __bridge_retained __bridge_transfer 涉及所有权转换问题;







    

0 0