资讯专栏INFORMATION COLUMN

Objective-C 内存管理的历史和参考资料

cartoon / 2490人阅读

摘要:早期引用计数的内存管理继承自,拥有一套基于对象引用计数的内存管理体系。这种引用计数的思想在很多地方也有应用,不过本质上说,仍然是需要程序员来手动管理计数的,只不过当计数值清零时,对象会被自动释放罢了。

原文:Objective-c 内存管理的历史和参考资料

对于像我这样自学IOS开发的初学者,网上有很多资料,很多教程,但是过于多的资料也使初学者无法筛选合适自己的。并且Objective-c也经历了几个阶段的演变,初学者有时更加会觉得迷茫了。本文总结一下Objective-c在内存管理上的一些问题,整理一些合适的资料。

早期:引用计数的内存管理

Objective-c继承自C,拥有一套基于对象引用计数的内存管理体系。这跟C#或者Java的垃圾回收机制不同,倒是与C++后来的智能指针有些类似。这种引用计数的思想在很多地方也有应用,不过本质上说,仍然是需要程序员来手动管理计数的,只不过当计数值清零时,对象会被自动释放罢了。

类似的代码如下,请注意注释:

objectivec//申请内存,并调用初始化,返回指针
//alloc会使得对象的引用计数初始化为1
Engine *engine1 = [[Engine alloc] init]; 

//调用retain,等同于使引用计数+1
[engine1 retain];

//调用release,等同于使引用计数-1
//只有当引用计数为0时,对象才会释放
[engine1 release];

即程序员需要来回的使用allocretainrelease控制对象的引用计数

属性与编译器约定

在遇到复杂面向对象编程的时候更为棘手,假设有一个类,其中包含有多个属性,这些属性都是指针类型,指向堆上的内存:

objectivec@interface Person
{
    NSString *Name;
    NSString *Address;
}

于是乎,当无论在什么时候,Person类的实例都将拥有对NameAddress两块内存的所有权。如果申请这两块内存的代码不是Person类自己的代码。那么Person需要使用retain增加引用计数,并在析构中负责release。那么很容易想到使用setget这对方法,对类的字段进行封装,以Name为例:

objectivec-(void) setName:(NSString *)name{
    if(self.Name != name){
        [Name release];
        Name = [name retain];
    }
}

-(NSString *) getName {
    return Name;
}

-(void)dealloc{
    [self setName:nil];
    [super dealloc];
}

在上面的setget方法中,封装了对内存的管理部分。为了简化这种需求,编译器直接通过编译支持这种写法,即我们可以通过下面的代码代替上面的setget函数,编译器会自动按照上面的代码展开:

objectivec@interface Person
@property (retain) NSString* Name;
@end


@implementation Person
@synthesize Name;
@end

于是在使用属性的时候可以这么做:

Person *person = [[Person alloc] init];
person.Name = @"Jack";

实际上编译器对上述调用代码同样会展开成setName函数。这就是“点语法”,看起来是不是跟大部分的语言的属性访问有些接近了。

自动释放池

后来开始出现自动释放池(Auto release pool),这个东西的出现简单的说是基于一种十分常见确很难处理的场景:需要在一个方法内部申请内存,并将内存的地址返回给调用者,这个时候谁来释放这个内存?如下面的代码:

-(ClassA *) Func1
{
    //内部申请空间,obj引用计数为1
    ClassA *obj = [[ClassA alloc] init];
    //返回这个申请的内存
    return obj;
    //谁来负责释放???
}

这个梗其实在任何非垃圾回收的语言中都存在,需要人为约定,要么创建者释放,要么调用者释放。试想,如果是创建者释放,那么创建者怎么知道调用者什么时候结束调用呢?如果是调用者释放,又会因为协同开发的原因,造成调用者忘记释放的情况。

OC发明了自动释放池的概念,上面的代码可以这样写:

objectivec-(ClassA *) Func1
{
    //内部申请空间,obj引用计数为1,使用autorelease延迟释放
    ClassA *obj = [[[ClassA alloc] init] autorelease];
    //返回这个申请的内存
    return obj;
}

使用autorelease方法,实际上的结果是本地变量obj的引用在自动释放池中保留一份,并在恰当的时候,释放掉。具体原理参加下面给出的资料链接。

事实上从程序结构上看,OC选择了谁申请谁释放的原则。至此,著名的黄金法则出现了,遵循黄金法则的代码不会出现内存泄露

  

The basic rule to apple is everything that increases the reference counter with alloc,[mutable]copy[WithZone:] or retain is in charge of the corresponding [auto]release.
如果一个对象使用了alloc,[mutable] copy,retain,那么必须使用相应的release或autorelease

详细的早期内存管理的资料参考:

iOS:内存管理(一):OC中的内存管理
iOS:内存管理(二):怎样在xcode里面使用Memory Leaks和Instruments教程
iOS:内存管理(三):在Objective-c里面使用property教程

Objective-C的内存管理(一)黄金法则的理解
Objective-C的内存管理(二)autorelease的理解

上面是早期的内存管理原理的机制,个人觉得还是需要深刻理解的,虽然现在基本都不这么写了,下面会说到

目前:自动引用计数

自动引用计数(Auto reference counting)后来被引入,实际上是编译器功能的大幅增强。现在开发IOS,默认都是开启ARC功能的。并在在ARC下,甚至是不允许写releaseretainautorelease这样的方法的。如果初学者从网上的资料中学习了,上面早期的一些知识,需要注意,实际做的时候基本都是使用ARC的(不少较新的OC程序员甚至已经不会手动管理内存了)。个人实际操作下来,感觉使用ARC,基本跟写C#没有什么太大的差别。这真心是有赖于编译器的强大。

在ARC下,并没有少了引用计数这个环节,从ARC的字面来看,实际上是编译器帮程序员完成了对引用计数的增减。而且ARC也有相应的编码约定或规范,在学习之前,还是需要学习早期的内存管理体系的。

参考资料如下:

转向ARC的说明——翻译Apple官方文档

本文总结了关于Objective-c中的内存管理方面的基础内容,希望对初学者有个启发

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/15722.html

相关文章

  • 「技术专栏」这些年我们爱着 Objective-C

    摘要:成长年,和成立了公司,并发布了第一个实现。动态语义是通过一个来实现的,这个逐渐发展成了现在的简称。将这一新的实现称为,也就是我们现在看到的这个样子。困难之一是与和之间的协调。但最终克服了重重障碍,成为管理依赖的首选。 showImg(https://segmentfault.com/img/remote/1460000006768947); 文 / 唐天勇 LeanCloud 工程师 ...

    econi 评论0 收藏0
  • iOS 学习资料整理(上)

    摘要:看到一份很赞的学习资料,由于文章字数限制,分两篇分享原文学习资料整理这份学习资料是为初学者所准备的旨在帮助初学者们快速找到适合自己的学习资料节省他们搜索资料的时间使他们更好的规划好自己的学习路线更快的入门更准确的定位的目前所处的位置该文档会 看到一份很赞的IOS学习资料,由于SF文章字数限制,分两篇分享 原文 iOS 学习资料整理 这份学习资料是为 iOS 初学者所准备的, 旨在帮助...

    church 评论0 收藏0
  • 所谓,引用计数

    摘要:每个对象有一个与之相关联的整数,称作它的引用计数器。当该代码结束访问时,将该对象的引用计数器值减。图中红色表示引用计数的活动。当然,引用计数也有一些缺点无法完全解决循环引用导致的内存泄露问题。即使只读操作,也会引起内存写操作引用计数的修改。 博文链接: http://ifujun.com/suo-wei-yin-yong-ji-shu/ 简介 在大部分关于Objective-C的书中,...

    zhaofeihao 评论0 收藏0
  • Objective-C内存管理(1)——内存管理概述

    摘要:基于某些机制实现半自动管理这里的某些机制其实通常就是引用计数。早年,选择的是退一步,完全让程序员来管理引用计数的加减,称为,显然管理成本偏高。 概述 应用程序开发中,内存管理是个重要的话题。简单而言,语言层面的内存管理基本有三类: 1. 纯粹的手动管理 如C和曾经的C++。 char *some_string = malloc(BUFFER_SIZE); // do something...

    zzbo 评论0 收藏0
  • 【超齐全】iOS 学习资料整理

    好赶货,收藏。原文iOS 学习资料整理 这份学习资料是为 iOS 初学者所准备的, 旨在帮助 iOS 初学者们快速找到适合自己的学习资料, 节省他们搜索资料的时间, 使他们更好的规划好自己的 iOS 学习路线, 更快的入门, 更准确的定位的目前所处的位置. 该文档会持续更新, 同时也欢迎更多具有丰富经验的 iOS 开发者将自己的常用的一些工具, 学习资料, 学习心得等分享上来, 我将定期筛选合...

    Flands 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<