Objective-C 内存管理

本文深入探讨Objective-C中的内存管理机制,包括引用计数器的工作原理、MRC与ARC的区别及应用,通过实例演示如何管理对象的生命周期。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

前两篇中Objective-C属性,在定义属性时我们使用一系列关键字,比如:retain,release,assgin,copy,strong,weak等等,那么这些关键字到底在程序运行起什么作用呢?下面我们通过内存管理来深刻的理解这些词的具体作用。

介绍

内存管理:程序在运行过程中,会创建很多的类和对象,而创建类和对象就要占用内存空间,基本类型都是系统自动管理放在栈区,而创建的类和对象放在堆区,我们得手动管理这篇区域的内存使用情况。

Objc作为高级程序语言是怎么管理的呢? 像java内存管理有垃圾回收机制(gc),Objc的内存并没有垃圾回收机制,难道让我们自己去内存中找到对应地址释放内存吗,当然不是如果是这样就脱离高级语言了,我们要引入“引用计数器”我们通过这个管理内存。我们先来看看这个神秘东东的介绍吧。

引用计数器

引用计数器:Objc在创建类和对象的时候,内部会默认给类和对象添加一个计数器一样的属性(retainCount),来表明其使用情况。当一个类和对象的时候,这个计数器(retainCount)就会加1,在不适用这个类的时候,计数器减1,当计数器为0时,就会释放内存空间。

retain,copy 计数器就会+1;而我们在创建类和对象所使用的new和alloc同样也会使计数器+1.

当我们调用release的时候计数器相对应-1,当计数器为0时,自动调用dealloc方法释放内存。

Objc目前为我们提供了两种内存管理,MRC和ARC分别为手动内存管理和自动内存管理,ARC是从Xcode4.2开始使用的,也是苹果公司推荐的内存管理方式。以下我们详细介绍这两种。

MRC手动内存管理

MRC(MannulReference Counting)手动内存管理,顾名思义就是需要我们(开发者)管理每一个使用的类和对象,手动编写retain和release,需要我们对内存的管理更加深刻。当然想要更加深刻学习Objc内存管理还是来使用MRC吧。在痛苦中挣扎,黑暗中觉醒,哈哈。

现在默认是ARC,使用MRC需要我们手动开启:项目属性—Build Settings–搜索“garbage”找到Objective-C Automatic Reference Counting设置为NO。

我们将通过一个Person类来学习

#import <Foundation/Foundation.h>

@interface Person : NSObject

#pragma mark - 属性
@property (nonatomic,copy) NSString *name;
@property (nonatomic,assign) NSInteger age;

@end
#import "Person.h"

@implementation Person
//重写dealloc方法 方便观察
-(void)dealloc{
    NSLog(@"Invoke Person's dealloc method.");
    [super dealloc];
}
-(void) test{
    Person *teach = [[Person alloc]init]; //alloc 开辟内存空间 引用计数器+1
    teach.name = @"gavin";
    teach.age = 26;

    Person *student = [Person new]; //new 相当于alloc + init 同样开辟内存空间 引用计数器+1
    student.name = @"alice";
    student.age = 20;

    //这个时候我们不需要teach这个对象要释放
    [teach release]; //如果我们使用这样的方法,teach指针指向的内存空间释放了,但是这个指针还是存在的,那么我以后如果不小心调用这个指针,有可能得到一个异常的结果,或者直接崩溃。这就是野指针也就是空指针。
    //正确的使用姿势
    //首先让指针为空
    teach = nil;
    [teach release];

    //使用retain,使得引用计数器+1 
    [student retain];

    //可以查看引用计数器变化
    NSLog(@"retainCount=%lu",[p retainCount]);

    //使用release,引用计数器-1
    [student release]; 

    //使用copy查看内存变化
    Person *alice = [teach copy];
    /*
        使用copy,需要注意看我们的具体需要:这里面涉及深拷贝和浅拷贝。
        深拷贝:mutableCopy 相当于复制一个副本,原件的改变不会影响副本。
        浅拷贝:copy 相当retain,使当前对象teach的引用计数器+1;
    */


}

内存的释放

内存的释放遵循:谁创建,谁释放 的原则,而往往在实际开发过程错综复杂调用和对象之间相互交叉引用使得这个过程相对不是那么容易。ARC的出现使得开发者效率大大提高。但是在内存使用也需要注意循环引用。

ARC自动内存管理

ARC(Automatic Reference Counting)自动内存管理,相比较MRC,我们(开发者)不需要在内存管理上花费大量的开发时间,我们可以专注的开发业务代码,调用相应的方法,在程序编译的时候自动帮我们加上retain和release。
ARC具体介绍可以查看 官方文档 摘出来一些方便查看:

变量修饰符可以使用如下修饰符:
__strong
__weak
__unsafe_unretained
__autoreleasing
__strong: 默认限定符,不需要显式指定。表示任何用alloc/init创建的对象在当前范围的生命期内得以保留。“当前范围”是指变量声明语句所在的两个大括号之间(方法、循环、块,等等)。
__weak: 表示对象可以随时被摧毁。只有当它被其它对象强引用时才有用。__weak变量在摧毁时,被设为nil。
__unsafe_unretained: 与__weak类似,但在摧毁时,不设为nil,保留原值(不再指向有效的东西)。
__autoreleasing: 不要与autorelease搞混,它用于通过引用传递对象,比如,通过引用传递NSError对象: [myObject performOperationWithError:&tmp]。

@autoreleasepool 自动释放池

在ObjC中也有一种内存自动释放的机制叫做“自动引用计数”(或“自动释放池”),一般给只使用一次的对象发送这样的消息。如:

Person *teach = [[[Person alloc]init]autorelease];//这样用是姿势不对

//我们看看正确姿势
//首先我们建立自动释放池
id pool = [[NSAutoreleasePool alloc]init];
//创建对象
Person *teach = [[Person alloc]init];
//添加自动释放
[teach autorelease];
//这个时候我们添加到自动释放池中,只要缓存池没有释放,对象依然可以使用
teach.name = @"gavin";
//pool缓存池释放
[pool release];

PS

对于内存管理在实际开发还会遇到各种各样的问题,循环引用,还有就是开发过程中的内存泄漏,编写代码中找到也是需要慢慢调试,这里使用Instruments工具来检查内存使用情况,这个工具还有许多功能,比如可以查看启动时间,内存使用情况等等功能。在之后在介绍。以上内容如果发现有错误请留言或联系宝宝
祝大家新春快乐,大年除夕晚上来写这一篇,希望对大家有帮助。鸡年大吉!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值