前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Cocoa内存管理的简单规则[翻译]

Cocoa内存管理的简单规则[翻译]

作者头像
EltonZheng
发布于 2021-01-26 07:01:02
发布于 2021-01-26 07:01:02
53800
代码可运行
举报
运行总次数:0
代码可运行

看了一篇mmalcolm crawford写的文章,觉得不错, 原文在此。比较清楚的讲解了Cocoa的内存管理。 对于Mac和iPhone的开发有很大帮助。 特翻译并略做修改以方便理解,希望与大家共勉

对于一个新的Cocoa开发者来说,刚接触到内存管理的时候,一定很困惑。 下面给出了一些简单的规则,可以让你舒服些。如果你没有很好的使用这些规则的话,通常会带来内存泄露的问题或者运行时的异常。

Cocoa过去没有垃圾回收机制,iPhone现在也没有。所以你必须自己来通过-retain, -release and -autorelease这些命令使用引用计数(reference counting)技术来管理内存。

方法

描述

-retain

给一个对象的引用计数加1

-release

给一个对象的引用计数减1

-autorelease

在将来的某些时候将一个对象的引用计数减1

-alloc

分配一块内存给对象,引用计数器将设为1

-copy

拷贝一个对象,将返回引用计数为1的一个对象

引用计数规则

  1. \u000a在你的方法中使用了-copy\u000a, \u000a-alloc\u000a 和 \u000a-retain来申请内存,就要对应的使用\u000a\u000a-release\u000a 和 \u000a-autorelease来释放内存;\u000a
  2. 当对象使用便捷方法创建的时候(如:NSString类的 stringWithString方法),则这个对象将被视为已经使用了\u000aautorelease,在将来某时自动释放内存;\u000a
  3. 如果你定义了实例变量,则在你的类中实现\u000a-dealloc这个方法来释放他们。\u000a

例子:

-alloc / -release

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- (void)printHello
{
	NSString *string;
	string = [[NSString alloc] initWithString:@"Hello"];
	NSLog(string);
	// 我们使用alloc来创建了一个string 所以要release它
	[string release];
}

便捷构造方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- (void)printHello
{
    NSString *string;
    string = [NSString stringWithFormat:@"Hello"];
    NSLog(string);
    // 我们构建这个string的时候,使用了便捷构造方法( convenience constructor )
    // 所以我们认为它是 autoreleased的
}

永远使用accessor方法

有时候你会觉得使用accessor方法会比较教条和无聊,但是使用他们会降低内存泄露的机会。

如果对于实例变量你也使用 -retain 和-release 来管理内存的话,那就错了。

例子 在接口中定义了一个实例变量

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@interface Counter : NSObject
{
	NSNumber *count;
}

在实现中加入accessor方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- (NSNumber *)count
{
	return count;
	// 不需要retain或者release
	// 我们只是返回这个变量的值
}

- (void)setCount:(NSNumber *)newCount
{

	// 如果每个人都使用上述同样的内存管理规则
	// 我们就得认为newCount是autoreleased的。
	// 因为我们想使用这个变量,所以我们必须retain它
	// 避免它被释放掉。
	[newCount retain];

	// 因为我们只想在这个方法中改变这个类中的count值
	// 所以要通过这个方法,先释放掉之前的内存
	// 在Objective-C中[nil release]也是被允许的
	// 我们必须将次调用放在 [newCount retain] 的后面
	// 因为如果当count和newCount都指向同一个对象的时候
	// 我们会错误的释放它
	[count release];

	// 关联新的引用
	count = newCount;
}

因为我们的类有实例变量,所以需要实现-dealloc方法来释放内存。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- (void)dealloc
{
	[self setCount:nil];
	[super dealloc];
}

假设我们需要一个重置count的值的方法,我们有两个选择

便捷构造方法convenience constructor

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- (void)reset
{
	NSNumber *zero = [NSNumber numberWithInt:0];
	[self setCount:zero];
}

使用-alloc方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- (void)reset
{
	NSNumber *zero = [[NSNumber alloc] initWithInt:0];
	[self setCount:zero];
	[zero release];
}

常见错误

下面的问题在一些简单的环境下可能会正常工作,但是避开使用accessor方法,在某些时候几乎可以肯定会带来内存泄露的问题。

没有使用accessor方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- (void)reset
{
	NSNumber *zero = [[NSNumber alloc] initWithInt:0];
	[count release]
	count = zero;
}

变量没有释放

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- (void)reset
{
	NSNumber *zero = [[NSNumber alloc] initWithInt:0];
	[self setCount:zero];
}

当使用alloc创建一个新对象的时候,retain count是1,如果我们没有在这个方法中使用-release方法,这个number对象将永远不能被释放,将会造成内存泄露。

已经释放内存的变量再次调用release

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- (void)reset
{
	NSNumber *zero = [NSNumber numberWithInt:0];
	[self setCount:zero];
	[zero release];
}

这将导致当你第一次访问count的时候发生错误。 便捷构造方法将返回一个autoreleased对象,所以你不必使用release。 在使用autoreleased后这样做,将减少count的计数到0,这个对象将被释放。当你之后视图访问count的时候,你将向一个自由对象(free object)发送调用消息(message),通常你将得到一个SIGBUS 10的错误。

经常让人混淆迷惑的问题 - 数组和其他集合类

当一个对象被添加到一个array, dictionary, 或者 set等这样的集合类型中的时候,集合会retain它。 对应的,当集合类被release的时候,它会发送对应的release消息给包含在其中的对象。 因此,如果你想建立一个包含一堆number的数组,你可以像下面示例中的几个方法来做

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
NSMutableArray *array;
    int i;
    // ...
    for (i = 0; i < 10; i++)
    {
        NSNumber *n = [NSNumber numberWithInt: i];
        [array addObject: n];
    }

在这种情况下, 我们不需要retain这些number,因为array将替我们这么做。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
NSMutableArray *array;
    int i;
    // ...
    for (i = 0; i < 10; i++)
    {
        NSNumber *n = [[NSNumber alloc] initWithInt: i];
        [array addObject: n];
        [n release];
    }

在这个例子中,因为你使用了-alloc去建立了一个number,所以你必须显式的-release它,以保证retain count的平衡。因为将number加入数组的时候,已经retain它了,所以数组中的number变量不会被release


本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
iOS - 老生常谈内存管理(二):从 MRC 说起
MRC全称Manual Reference Counting,也称为MRR(manual retain-release),手动引用计数内存管理,即开发者需要手动控制对象的引用计数来管理对象的内存。
师大小海腾
2020/04/24
1.7K0
iOS - 老生常谈内存管理(二):从 MRC 说起
高级内存管理指南
好的习惯可以防止内存相关的问题 a) 在反复使用同一个数据时释放掉或者覆盖掉。 b) 当数据不再被使用时如果不释放掉,会造成内存泄露。 基本的内存管理准则: a) 你拥有你创建的任何对象的管理权。诸如:alloc,copy,new,mutableCopy, 等待创建的对象适用此规则。 b) 使用了retain的对象你需要管理。 在以下两种情况下你要使用retain: i. 实现了访问方法,或者一个init方法; ii. 保证一个对象不被其它操作引起失效
nimomeng
2018/09/13
4040
浅谈iOS内存管理机制
iOS内存管理机制的原理是引用计数,引用计数简单来说就是统计一块内存的所有权,当这块内存被创建出来的时候,它的引用计数从0增加到1,表示有一个对象或指针持有这块内存,拥有这块内存的所有权,如果这时候有另外一个对象或指针指向这块内存,那么为了表示这个后来的对象或指针对这块内存的所有权,引用计数加1变为2,之后若有一个对象或指针不再指向这块内存时,引用计数减1,表示这个对象或指针不再拥有这块内存的所有权,当一块内存的引用计数变为0,表示没有任何对象或指针持有这块内存,系统便会立刻释放掉这块内存。 其中在开发时引
且行且珍惜_iOS
2018/05/22
1.2K0
objective-C 的内存管理之-自动释放池(autorelease pool)
如果一个对象的生命周期显而易见,很容易就知道什么时候该new一个对象,什么时候不再需要使用,这种情况下,直接用手动的retain和release来判定其生死足矣。但是有些时候,想知道某个对象在什么时候不再使用并不那么容易。如果下面的代码,看上去非常简单: Sample.h类接口部分 #import < Foundation / Foundation.h > @interface Sample : NSObject { } -(NSString*) toString; @end Sample.m 类实现
菩提树下的杨过
2018/01/22
1.1K0
Objective-C内存管理指南
本文翻译自Advanced Memory Management Programming Guide
Helloted
2022/06/07
4540
Objective-C内存管理指南
iPhone/Mac Objective-C内存管理教程和原理剖析(一)基本原理
前言 初学objectice-C的朋友都有一个困惑,总觉得对objective-C的内存管理机制琢磨不透,程序经常内存泄漏或莫名其妙的崩溃。我在这里总结了自己对objective-C内存管理机制的研究成果和经验,写了这么一个由浅入深的教程。希望对大家有所帮助,也欢迎大家一起探讨。
EltonZheng
2021/01/26
3520
OC中内存管理的一些问题
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010105969/article/details/46944979
用户1451823
2018/09/13
7570
OC学习10——内存管理
1、对于面向对象的语言,程序需要不断地创建对象。这些对象都是保存在堆内存中,而我们的指针变量中保存的是这些对象在堆内存中的地址,当该对象使用结束之后,指针变量指向其他对象或者指向nil时,这个对象将称为无用对象,因为没有指针指向它了,这种情况称为内存泄漏。当内存泄漏非常严重时,会导致内存不够用,程序就会崩掉。因此,内存管理是学习面向对象语言中非常重要也是非常头疼的一个问题。在Java、C++、OC等语言中都涉及到这些问题,Java的内存管理是非常轻松的,因为这些内存管理的工作都由虚拟机自动去完成,不需要程序
mukekeheart
2018/02/27
6400
OC学习10——内存管理
iOS内存管理(一)-基本的概念
weak引用表会用对象的地址作为key,所有指向指向对象指针的地址作为value数组
用户6658895
2023/07/20
4660
OC知识--彻底理解内存管理(MRC、ARC)
本文首发于我的个人博客:『不羁阁』 https://bujige.net 文章链接:https://bujige.net/blog/iOS-Memory-management.html 1. 什么是内存管理 程序在运行的过程中通常通过以下行为,来增加程序的的内存占用 创建一个OC对象 定义一个变量 调用一个函数或者方法 而一个移动设备的内存是有限的,每个软件所能占用的内存也是有限的 当程序所占用的内存较多时,系统就会发出内存警告,这时就得回收一些不需要再使用的内存空间。比如回收一些不需要使用的对象
程序员充电站
2018/05/31
4.7K0
iOS - 老生常谈内存管理(三):ARC 面世
ARC全称Automatic Reference Counting,自动引用计数内存管理,是苹果在 iOS 5、OS X Lion 引入的新的内存管理技术。ARC是一种编译器功能,它通过LLVM编译器和Runtime协作来进行自动管理内存。LLVM编译器会在编译时在合适的地方为 OC 对象插入retain、release和autorelease代码来自动管理对象的内存,省去了在MRC手动引用计数下手动插入这些代码的工作,减轻了开发者的工作量,让开发者可以专注于应用程序的代码、对象图以及对象间的关系上。   本文通过讲解MRC到ARC的转变、ARC规则以及使用注意,来帮助大家掌握iOS的内存管理。   下图是苹果官方文档给出的从MRC到ARC的转变。
师大小海腾
2020/04/24
2.4K0
iOS - 老生常谈内存管理(三):ARC 面世
iOS中内存管理
OC语言使用引用计数来管理内存,每一个对象都有一个可以递增递减的计数器,如果引用这个对象,那么这个对象的引用计数递增,如果不用了,那么这个对象引用计数递减,直到引用计数为0,这个对象就可以销毁了
xy_ss
2023/11/22
3380
内存管理、属性关键字
每当对象创建出来,它的生命就已经开始了,一直到操作系统释放了 该对象,对象的生命才结束
Helloted
2022/06/07
4660
iOS 内存管理相关面试题
保证任何时候指向对象的指针个数和对象的引用计数相同,多一个指针指向这个对象这个对象的引用计数就加1,少一个指针指向这个对象这个对象的引用计数就减1。没有指针指向这个对象对象就被释放了。
iOSSir
2019/06/14
1.6K0
Objective-C 内存管理(上)学习笔记
这里的“计数”表明必然会有一个东西(变量)来记录引用的变化,而在OC里这个变量就是retainCount;那么还有一个问题就是通过什么方式来操作这个变量,OC里就是retain(引用次数加 1),release(引用计数减 1 )方法。
半纸渊
2018/09/04
8430
Objective-C 内存管理(上)学习笔记
OC内存管理
OC内存管理 一、基本原理 (一)为什么要进行内存管理。 由于移动设备的内存极其有限,所以每个APP所占的内存也是有限制的,当app所占用的内存较多时,系统就会发出内存警告,这时需要回收一些不需要再继续使用的内存空间,比如回收一些不再使用的对象和变量等。 管理范围:任何继承NSObject的对象,对其他的基本数据类型无效。 本质原因是因为对象和其他数据类型在系统中的存储空间不一样,其它局部变量主要存放于栈中,而对象存储于堆中,当代码块结束时这个代码块中涉及的所有局部变量会被回收,指向对象的指针也被回收,此时
用户1941540
2018/05/11
9990
内存管理总结-autoreleasePool
转自其他 序言 无论是在MRC时期还是ARC时期,做过开发的程序员都接触过autoreleasepool。尽管接触过但本人对它还不是很了解。本文只是将自己的理解说出来。在内存管理的文章中提到了OC的内存管理是通过引用计数来完成的,也介绍了可以通过内存管理的方法(alloc/retain/new/copy等)来使引用计数加1,使用release方法来使引用计数减1。在我们创建了大量对象的时候,如果还是手动调用release方法来释放它们就显得太繁琐了。本文章将介绍内存管理的另外一种机制-autorelease
用户1941540
2018/05/11
1.3K0
iOS应用开发:什么是ARC
ARC是什么 ARC是iOS 5推出的新功能,全称叫 ARC(Automatic Reference Counting)。简单地说,就是代码中自动加入了retain/release,原先需要手动添加的用来处理内存管理的引用计数的代码可以自动地由编译器完成了。 该机能在 iOS 5/ Mac OS X 10.7 开始导入,利用 Xcode4.2 可以使用该机能。简单地理解ARC,就是通过指定的语法,让编译器(LLVM 3.0)在编译代码时,自动生成实例的引用计数管理部分代码。有一点,ARC并不是GC,它只是一
猿人谷
2018/01/17
1.2K0
iOS应用开发:什么是ARC
iOS 开发:彻底理解 iOS 内存管理(ARC 篇)
「引用计数式内存管理」的本质部分在 ARC 中并没有改变,ARC 只是自动帮我们处理了「引用计数」的相关部分。
程序员充电站
2021/11/24
6620
oc的内存管理机制
OC中每个对象都有一个与之对应的整数,叫“引用计数器”,当一个对象在创建之后它的引用计数器值加1,当调用这个对象的alloc、retain、new、copy方法之后引用计数器值自动在原来的基础上加1,当调用这个对象的release方法之后它的引用计数器值减1,如果一个对象的引用计数器值为0,则系统会自动调用这个对象的dealloc方法来销毁这个对象。
编程那点事
2023/02/25
3240
相关推荐
iOS - 老生常谈内存管理(二):从 MRC 说起
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验