iOS 底层 - OC对象内存管理之MRC

2020-04-15  本文已影响0人  水中的蓝天

本文源自本人的学习记录整理与理解,其中参考阅读了部分优秀的博客和书籍,尽量以通俗简单的语句转述。引用到的地方如有遗漏或未能一一列举原文出处还望见谅与指出,另文章内容如有不妥之处还望指教,万分感谢 !

作为一名开发者来说对内存管理一定不会感到陌生,那么内存管理到底是管理哪部分的内存呢?

iOS 程序内存布局比较了解的应该会知道内存布局分为:保留区、代码段、数据段、堆区、栈区、内核区;真正需要开发者参与管理的是:在堆空间申请的内存;如果程序员不释放,程序结束后,会由操作系统回收; 这里的结束也有可能是 崩溃导致 的结束

我多句嘴啊,为什么栈空间不需要开发者参与管理内存 ?

对啊,这是为什么呢 ? 嗯 原来是由编译器自动分配释放,所以不需要开发者参与咯 !

简单描述栈空间的内存管理原则 ?

分配:编译阶段由编译器来给参数值、局部变量等分配存储空间
释放:当超出其作用域时,由编译器控制从栈中弹出。

Manual Reference Counting :MRC, 手动引用计数

Automatic Reference Counting : ARC ,自动引用计数

OC对象的内存管理原则:

内存管理的经验总结

MRC环境OC对象的声明示例

@property (nonatomic, retain)XYHCar  *car;

- (void)dealloc
{
//    [_car release];
//    _car = nil;
//或
    self.car = nil;    
    // 父类的dealloc放到最后
    [super dealloc];
}

void _objc_autoreleasePoolPrint(void)

这很奇怪,既然是私有函数怎么能够被外界调用呢 ?怎么做到的呢 ?
可以的,使用 extern 关键字(前提是该函数没有被struct修饰为静态方法)对该函数在需要用到的地方重新声明一遍,真正调用时编译器会去查找有没有这个函数,只要有就会调用啦 ! 比如:

示例代码

传入void表示没有参数
extern void _objc_autoreleasePoolPrint(void);

int main(int argc, const char * argv[]) {
   @autoreleasepool { //  r1 = push()
       
       XYHOlg *olg1 = [[[XYHOlg alloc] init] autorelease];
       XYHOlg *olg2 = [[[XYHOlg alloc] init] autorelease];
       
       @autoreleasepool { // r2 = push()
           for (int i = 0; i < 6; i++) {
               XYHOlg *olg3 = [[[XYHOlg alloc] init] autorelease];
               NSLog(@"%@",olg3);
           }
           @autoreleasepool { // r3 = push()
               XYHOlg *olg4 = [[[XYHOlg alloc] init] autorelease];
               _objc_autoreleasePoolPrint();
               NSLog(@"%@,%@,%@",olg1,olg2,olg4);
           } // pop(r3)
       } // pop(r2)
       
   } // pop(r1)
   
   return 0;
}

输出结果
(hot) :当前 pool page
(cold):不是当前 pool page
(hot)(cold): 就一个pool page,怎么着都行

objc[1363]: ##############
objc[1363]: AUTORELEASE POOLS for thread 0x1000d1dc0
objc[1363]: 12 releases pending.
objc[1363]: [0x100805000]  ................  PAGE  (hot) (cold)
objc[1363]: [0x100805038]  ################  POOL 0x100805038 第一个自动释放池
objc[1363]: [0x100805040]       0x10051fbc0  XYHOlg
objc[1363]: [0x100805048]       0x10051fc10  XYHOlg
objc[1363]: [0x100805050]  ################  POOL 0x100805050 第二个自动释放池
objc[1363]: [0x100805058]       0x10051fc20  XYHOlg
objc[1363]: [0x100805060]       0x10051fc30  XYHOlg
objc[1363]: [0x100805068]       0x100520130  XYHOlg
objc[1363]: [0x100805070]       0x100520140  XYHOlg
objc[1363]: [0x100805078]       0x100520150  XYHOlg
objc[1363]: [0x100805080]       0x100520160  XYHOlg
objc[1363]: [0x100805088]  ################  POOL 0x100805088 第三个自动释放池
objc[1363]: [0x100805090]       0x100520170  XYHOlg
objc[1363]: ##############
Program ended with exit code: 0

release和autorelease的区别 ?

ARC环境声明OC对象可以用assign来修饰吗 ?为什么?

小小知识点:指针

注意:这里的内存管理 范围OC对象 ,至于基本数据类型如:intfloat不在范围之内;

OC对象的引用计数都是自然数吗 ?

绝大多数是的,只有NSString变NSTaggedPointerString时引用计数为其内存地址的十进制数

在开发中就没有需要用到OC对象之外的数据类型了吗 ?他们的内存管理该如何实现 ?

在iOS开发过程中可能会用到的语言有很多,比如:CC++RNSwiftJavascript等;这其中最多使用到是C的一些数组、字符串、指针, C语言中对堆内存的申请是调用malloc函数实现、释放是调用free函数实现;
Javascript 具有自动垃圾回收机制,执行环境会管理代码执行过程中使用的内存。

示例代码:

int _tmain(int argc, _TCHAR* argv[])
{
    char *p = (char *)malloc(1024*1024*1024);//在堆中申请了内存
    memset(p, 'a', sizeof(int) * 10);//初始化内存
    int i = 0;
    for (i = 0; i < 10; i++)
    {
        p[i] = i + 65;
    }
    print_array(p, 10);
    free(p);//释放申请的堆内存
}
上一篇 下一篇

猜你喜欢

热点阅读