ARC机制

2024-05-29 04:08
文章标签 机制 arc

本文主要是介绍ARC机制,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


一、ARC简介

ARC是自iOS 5之后增加的新特性,完全消除了手动管理内存的烦琐,编译器会自动在适当的地方插入适当的

retain、release、autorelease语句。开发者不再需要担心内存管理,因为编译器为你处理了一切

ARC 是编译器特性,而不是 iOS 运行时特性,它也不是类似于其它语言中的垃圾收集器。因此 ARC 和手动内

存管理性能是一样的,有时还能更加快速,因为编译器还可以执行某些优化

二、ARC原理

1、编译器如何自动管理内存

Clang编译器项目自带一个“静态分析器”,用于志明程序里应用计数出问题的地方,比如有Person类中有一个类方法

if(self == [Person Class])
{Person *p = [[self alloc] init];NSLog(@"%@",p);
}
else
{NSLog(@"%@是Person的子类",self);
}

由于if语句之外无法引用p,如果没有使用ARC机制,这段代码就会有内存泄漏,此时p对象内存中的计数器值为

1,因为没有相关语句来释放,所以这个对象会一直占据着它所在的内存空间。判定内存是否泄漏所用的规则很简

明:调用Person的alloc方法所返回的p对象的保留计数比期望值要多1,之后却没有与之对应的释放操作来抵消,计算

机可以将这些规则套用在程序上,从而分析出有内存泄漏问题的对象,“静态分析器”还可以根据需要,预先加入适当

的retain或release操作以避免内存泄漏的问题,自动引用计数正是源自于此。于是在前面那段代码的if语句结束之前,

可以于对象p上自动执行release操作,也就是把代码自动改写成以下形式:

if(self == [Person Class])
{Person *p = [[self alloc] init];NSLog(@"%@",p);[p release];
}
else
{NSLog(@"%@是Person的子类",self);
}

2、ARC对代码的优化

在编译期,ARC会把能够互相抵消的retain、release和autorelease操作约简,如果发现在同一个对象上执行了多

次保留和释放操作,那么ARC有时可以成对地移除这两个操作。比如有些方法在返回对象前执行了autorelease操作,

而调用方法地代码可能需要将返回地对象保留,例如在非ARC环境下有个初始化Person的类方法

+ (id)personWithAge:(int)age
{Person *p = [[[self alloc] init] autorelease];p.age = age;return p;
}>

假如当某个类里有个Person类的强引用成员变量_myPerson,当初始化该类时就可以有

<span style="font-size:18px;">_myPerson = [Person PersonWithAge:10];</span>

调用personWithAge方法会返回新的Person对象,而此方法在返回对象之前为其调用了autorelease方法,由于实例变

量_myPerson是个强引用,所以编译器在设置其值的时候还需要执行一次保留操作,因此,上面那句代码等价于下面

这段手工管理引用计数代码

Person *p = [Person personWithAge:10];
_myPerson = [p retain];


或者可以设想以下,当_myPerson = [p retain]该语句不执行retain操作,也就是直接_myPerson = p,那么当自动释放

池回收对象时,p对象的引用计数值刚好执行完release之后降为0,那么该内存对象就会被回收,而_myPerson就会指

向一个僵尸对象。

此时应该能看出personWithAge方法里的autorelease和上段代码中的retain操作时多余的,为提升性能,可以将

二者删去。

当ARC在运行期检测到这一对多余的操作时,也就是autorelease其后紧跟着retain,为了优化代码,在方法中返

回自动释放的对象时会执行一个特殊的函数,此时不直接调用对象的autorelease方法,而改为调用

objc_autoreleaseReturnValue。此函数会检视当前方法返回之后即将要执行的那段代码,若发现那段代码要在返回的

对象上执行retain操作,则设置全局数据结构中的一个标志位,而不执行autorelease操作。与之相似,如果方法返回

了一个自动释放的对象,而调用方法的代码要保留此对象,那么此时不执行retain,而是执行

objc_retainAutoreleaseReturnValue函数,此函数要检测刚才提到的那个标志位,若已置位,则不执行retain操作,设

置并检测标志位要比autorelease和retain更快。下面这段代码演示类ARC是如何优化程序的

在ARC编译环境下,对于Person类中的初始化的类方法

+ (id)personWithAge:(int)age
{Person *p = [[[self alloc] init] autorelease];p.age = age;objc_autoreleaseReturnValue(p);
}
而使用该方法时

<span style="font-size:18px;">Person *p = [Person personWithAge:10];
_myPerson = objc_retainAutoreleaseReturnValue(p);</span>

为了得到最佳效率,这些特殊函数得实现代码都会因处理器而异,下面得伪代码演示了这一步骤

id objc_autoreleaseReturnValue(id object)
{if(/*后面的代码有一次retain操作*/){set_flag(object);return object;		// 不会再进行autorelease操作}else{return [object autorelease];}
}id objc_retainAutoreleaseReturnValue(id object)
{if(get_flag(object))		// 即该retain操作前有autorelease{clear_flag(object);return object;		// 不再进行retain操作}else{return [object retain];}
}


objc_autoreleaseReturnValue函数是如何检测方法调用者是否会立刻retain对象呢,这要根据处理器来决定,也就是

只有编译器的开发者能实现此函数了。

三、ARC的使用

1、规则

ARC的规则非常简单,只要还有一个强指针指向对象,对象就会保持再内存中。

2、强指针和弱指针

默认所有实例变量和局部变量都是强指针;

弱指针指向的对象被回收后,弱指针会自动变成nil指针,不会引发野指针错误

3、使用注意

(1)不能调用release、retain、autorelease、retainCount、copy
(2)可以重写dealloc,但是不能调用[super dealloc]
(3)@property : 想长期拥有某个对象,应该用strong,其他对象用weak
(4)其他基本数据类型依然用assign
(5)两端互相引用时,一端用strong、一端用weak


代码示例:

	
#import <Foundation/Foundation.h>
@class Person;@interface Dog : NSObject
//谨记:@property后面跟着分号;
@property (nonatomic,strong) Person *person;
@end#import "Dog.h"@implementation Dog
- (void)dealloc
{NSLog(@"Dog is dealloc");// [super dealloc]; 不需要再调用了}
@end/*strong:表示该变量引用的是强指针(默认)weak:表示该变量引用的是弱指针(多用于对象循环引用)*/#import "Person.h"
//谨记:@class 类名;,后面跟分号;
@class Dog;@interface Person : NSObject@property (nonatomic,assign) int age;
//强指针类型
//@property (nonatomic,strong) Dog *dog;
//使用弱指针,当main函数执行完会先回收局部变量,因为指向够的指针是弱指针,所以狗对象会被释放,狗对象被释放之后里面的成员变量person也不存在了所以就不会指向person,所以person也会被释放
@property (nonatomic,weak) Dog *dog;@end#import "Person.h"@implementation Person
- (void) dealloc
{NSLog(@"age = %d Person---dealloc",_age);
}
@end/*指针:强指针:默认情况下,所有指针都是强指针 __strong弱指针:__weak,弱指针指向的对象会被回收*/
#import <Foundation/Foundation.h>
#import "Person.h"
#import "Dog.h"
int main()
{Person *p = [[Person alloc] init];Dog *d = [[Dog alloc] init];p.age = 10;/*当两个成员变量都是强指针且循环引用,则两个强指针一直互相指向则arc机制不会释放对象。p.dog = d;d.person = p;*/return 0;
}


这篇关于ARC机制的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1012605

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

【编程底层思考】垃圾收集机制,GC算法,垃圾收集器类型概述

Java的垃圾收集(Garbage Collection,GC)机制是Java语言的一大特色,它负责自动管理内存的回收,释放不再使用的对象所占用的内存。以下是对Java垃圾收集机制的详细介绍: 一、垃圾收集机制概述: 对象存活判断:垃圾收集器定期检查堆内存中的对象,判断哪些对象是“垃圾”,即不再被任何引用链直接或间接引用的对象。内存回收:将判断为垃圾的对象占用的内存进行回收,以便重新使用。

【Tools】大模型中的自注意力机制

摇来摇去摇碎点点的金黄 伸手牵来一片梦的霞光 南方的小巷推开多情的门窗 年轻和我们歌唱 摇来摇去摇着温柔的阳光 轻轻托起一件梦的衣裳 古老的都市每天都改变模样                      🎵 方芳《摇太阳》 自注意力机制(Self-Attention)是一种在Transformer等大模型中经常使用的注意力机制。该机制通过对输入序列中的每个元素计算与其他元素之间的相似性,

如何通俗理解注意力机制?

1、注意力机制(Attention Mechanism)是机器学习和深度学习中一种模拟人类注意力的方法,用于提高模型在处理大量信息时的效率和效果。通俗地理解,它就像是在一堆信息中找到最重要的部分,把注意力集中在这些关键点上,从而更好地完成任务。以下是几个简单的比喻来帮助理解注意力机制: 2、寻找重点:想象一下,你在阅读一篇文章的时候,有些段落特别重要,你会特别注意这些段落,反复阅读,而对其他部分

【Tools】大模型中的注意力机制

摇来摇去摇碎点点的金黄 伸手牵来一片梦的霞光 南方的小巷推开多情的门窗 年轻和我们歌唱 摇来摇去摇着温柔的阳光 轻轻托起一件梦的衣裳 古老的都市每天都改变模样                      🎵 方芳《摇太阳》 在大模型中,注意力机制是一种重要的技术,它被广泛应用于自然语言处理领域,特别是在机器翻译和语言模型中。 注意力机制的基本思想是通过计算输入序列中各个位置的权重,以确

FreeRTOS内部机制学习03(事件组内部机制)

文章目录 事件组使用的场景事件组的核心以及Set事件API做的事情事件组的特殊之处事件组为什么不关闭中断xEventGroupSetBitsFromISR内部是怎么做的? 事件组使用的场景 学校组织秋游,组长在等待: 张三:我到了 李四:我到了 王五:我到了 组长说:好,大家都到齐了,出发! 秋游回来第二天就要提交一篇心得报告,组长在焦急等待:张三、李四、王五谁先写好就交谁的

UVM:callback机制的意义和用法

1. 作用         Callback机制在UVM验证平台,最大用处就是为了提高验证平台的可重用性。在不创建复杂的OOP层次结构前提下,针对组件中的某些行为,在其之前后之后,内置一些函数,增加或者修改UVM组件的操作,增加新的功能,从而实现一个环境多个用例。此外还可以通过Callback机制构建异常的测试用例。 2. 使用步骤         (1)在UVM组件中内嵌callback函

Smarty模板引擎工作机制(一)

深入浅出Smarty模板引擎工作机制,我们将对比使用smarty模板引擎和没使用smarty模板引擎的两种开发方式的区别,并动手开发一个自己的模板引擎,以便加深对smarty模板引擎工作机制的理解。 在没有使用Smarty模板引擎的情况下,我们都是将PHP程序和网页模板合在一起编辑的,好比下面的源代码: <?php$title="深处浅出之Smarty模板引擎工作机制";$content=

Redis的rehash机制

在Redis中,键值对(Key-Value Pair)存储方式是由字典(Dict)保存的,而字典底层是通过哈希表来实现的。通过哈希表中的节点保存字典中的键值对。我们知道当HashMap中由于Hash冲突(负载因子)超过某个阈值时,出于链表性能的考虑,会进行Resize的操作。Redis也一样。 在redis的具体实现中,使用了一种叫做渐进式哈希(rehashing)的机制来提高字典的缩放效率,避