文章目录

  • 预备知识
  • 手动引用计数MRC
    • 自己生成的对象,自己持有
    • 非自己生成的对象,自己也能持有
    • 不再需要自己持有的对象时释放
    • 无法释放非自己持有的对象
  • @property参数
  • MRC中避免循环retain
  • retainCount
  • autorelease

预备知识

  1. 任何继承了NSObject的对象都需要进行内存管理,其他非对象类型(int、char、float、double、struct、enum等不需要进行内存管理
  • 继承了NSObject的对象存储在操作系统的堆里,堆一般由程序员分配释放,程序结束时可能有OS回收。
  • 非OC对象一般放在操作系统的栈里,栈由操作系统自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈(先进后出)

五大内存区域:栈区、堆区、全局区、常量区、代码区

  1. 内存管理模型
  • 自动垃圾收集
  • 手动引用计数 MRC
  • 自动引用计数 ARC

在项目中打开MRC

手动引用计数MRC

  • 引用计数器,可以理解为对象被引用的次数,每一个对象都有自己的引用计数器,引用计数为0时,对象占用的内存会被回收

内存管理的思考方式

  • 自己生成的对象,自己持有
  • 非自己生成的对象,自己也能持有
  • 不再需要自己持有的对象时释放
  • 非自己持有的对象无法释放

自己生成的对象,自己持有

使用alloc、new、copy、mutableCopy开头的方法意味着自己生成的对象只有自己持有,不需要retain

//自己生成并持有对象
id obj1 = [[NSObject alloc] init];
id obj2 = [[NSObject new];

非自己生成的对象,自己也能持有

用 alloc / new / copy / mutableCopy 以外的方法取得的对象,因为非自己生成并持有,所以自己不是该对象的持有者。
例如NSMutableArray类的array类方法。

id obj = [[NSMutableArray array];
[obj retain];

[NSMutableArray array] 相当于 [[[NSMutableArray alloc] init] autorelease];

使用autorelease方法,可以使取得的对象存在,但自己不持有对象。通过retain操作持有对象。

不再需要自己持有的对象时释放

id obj = [[NSObject alloc] init];//释放对象
[obj release];

无法释放非自己持有的对象

//这一部分存在疑惑
id obj = [[NSObject alloc] init];
[obj release];
[obj release];
NSLog(@"%p", obj);
  • 这段代码在执行NSLog时可能会报错,因为对象所占的内存在“解除分配”之后,只是放回了“可用内存池”。如果执行NSLog时尚未覆写对象内存,那么该对象仍然有效,这时程序不会崩溃,所以调试过程中可能结果不一样,为避免在不经意间使用了无效对象,一般调完release之后都会清空指针。这就能保证不会出现可能指向无效对象的指针,这种指针通常称为“悬挂指针”。
[obj release];
obj = nil;
  • 这部分存在疑惑的是,对obj进行第二次release操作时,应该会导致崩溃,但是并没有…

  • (补充)对于对象的内存回收的理解:当对象的被回收时,其所占有的内存空间就可以分配给别人,在没有分配给别人之前,对象的数据还存在。

@property参数

  • 在成员变量前加上@property,系统就会自动帮我们生成基本的setter/getter方法
@property (nonatomic) int val;
  • 如果在property后边加上retain,系统就会自动帮我们生成getter/setter方法内存管理的代码,但是仍需要我们自己重写dealloc方法
@property(nonatomic, retain) Room *room;
  • 如果在property后边加上assign,系统就不会帮我们生成set方法内存管理的代码,仅仅只会生成普通的getter/setter方法,默认什么都不写就是assign
@property(nonatomic, retain) int val;

MRC中避免循环retain

//Person.h
#import <Foundation/Foundation.h>
@class Son;NS_ASSUME_NONNULL_BEGIN@interface Person : NSObject@property (nonatomic, retain) Son *son;@end//Son.h
#import <Foundation/Foundation.h>
@class Person;
NS_ASSUME_NONNULL_BEGIN@interface Son : NSObject@property (nonatomic, retain) Person *p;@end
//main.m
Son *son = [[Son alloc] init];
Person *person = [[Person alloc] init];son.p = person;
person.son = son;[person release];
[son release];
[son release];

会造成内存泄漏,堆中的两个对象的内存回收不了
解决办法:

  • 一端用retain,一端用assign
//Person.h
@property (nonatomic, retain) Son *son;//Son.h
@property (nonatomic, assign) Person *p;

retainCount

NSObject协议中定义了下列方法,用于查询对象当前的引用计数
- (NSUInteger)retainCount;
ARC中已将此方法废弃

保留计数的绝对数值一般都与开发者所应留意的事情完全无关,即便在调试时会用到此方法,通常也还是无所助益的。
此方法之所以无用,首要原因在于:他所返回的保留计数只是某个给定时间点上的值。并未考虑到对象是否处于自动释放池中稍后系统会将自动释放池情况这种情况。
举个例子

while ([object retainCount]) {[object release];
}

有两个错误

  • 并未考虑到后续自动释放操作,只是不停通过释放操作降低保留计数,直至保留计数为0被系统回收,并未考虑到对象是否在自动释放池中。如果对象在自动释放池中,在系统清空池子时,会对对象再做一次release操作,这时就会导致程序崩溃。
  • retainCount可能永远不会返回0,因为有时系统会优化对象的释放行为,在保留计数还是1的时候就把它回收了。只有在系统不打算这么优化时,计数值才会递减至0。所以,这段代码可以正常运行,多半是运气。

在我们希望系统回收对象时,应确保没有尚未抵消的retain保留操作,避免内存泄漏。

保留计数值过大原因


打印结果:

前三个对象皆为“单例对象”,所以其保留计数都很大。

  • 系统会尽可能把NSString实现成单例对象。如果字符串像例子上的那样,是一个编译期常量,那么就可以这样来实现了。在这种情况下,编译器会把NSString对象所表示的数据放在应用程序的二进制文件里,这样的话,运行程序时就可以直接用了,无需再创建NSString对象。
  • NSNumber也类似,它使用了一种叫做“标签指针”的概念来标注指定类型的数值。这种做法不使用NSNumber对象,而是把与数值有关的全部消息都放在指针值里。运行期系统会在消息派发期间检测到这种标签指针,并对它执行相应操作,使其行为看上去和真正的NSNumber对象一样。这种优化只在某些场合使用,例子中的浮点数对象就没有优化,所以保留计数为1

对于上述所说的单例对象,其保留计数绝对不会改变。这种对象的保留及释放操作都是“空操作”。

打印结果:

2.0 36条中明确指出:不要使用retainCount
我们在MRC中,有时可能会想要打印引用计数,但retainCount方法并不是很有用,由于对象可能会处于自动释放池中,这会导致打印的引用计数并不精准,而且其他程序库也很有可能自行保留或释放对象,这都会扰乱引用计数的具体值。

autorelease

顾名思义,autorelease就是自动释放。
类似于C语言的局部变量,超出变量作用域,局部变量就会被废弃,不可再访问。
autorelease会在超出作用域时,调用对象的release实例方法,与C语言不同的是,编程人员可以设定变量的作用域
autorelease方法会返回对象本身,且调用完autorelease方法后,对象的计数器不变。autorelease实际上只是把对release的调用延迟了,对于每一个autorelease,系统只是把该对象放入了当前的autorelease pool中,当该pool被释放时,该pool中的所有对象会被调用release。
autorelease的具体使用方法如下:

  • 生成并持有NSAutoreleasePool对象
  • 调用已分配对象的autorelease实例方法
  • 废弃NSAutoreleasePool对象

对于所有调用过autorelease实例方法的对象,在废弃NSAutoreleasePool对象时,都将调用release实例方法。

内容不完整,后续补充

iOS内存管理—MRC相关推荐

  1. iOS 开发:彻底理解 iOS 内存管理(MRC 篇)

    本文首发于我的个人博客:「程序员充电站」 文章链接:「传送门」 本文更新时间:2021年08月17日17:11:59 本文是 「iOS 开发:彻底理解 iOS 内存管理」系列的「MRC 篇」. 用来对 ...

  2. 【Bugly干货分享】iOS内存管理:从MRC到ARC实践

    本文作者:王拥军 腾讯自选股高级开发工程师 Bugly 技术干货系列内容主要涉及移动开发方向,是由 Bugly 邀请腾讯内部各位技术大咖,通过日常工作经验的总结以及感悟撰写而成,内容均属原创. 对于i ...

  3. iOS内存管理(ARC,MRC)

    iOS内存管理方式: ARC Automatic Reference Counting 自动引用计数 MRC Manual Reference Counting 手动引用计数 更改管理方式: 内存管理 ...

  4. iOS内存管理机制解析

    软件运行时会分配和使用设备的内存资源,因此,在软件开发的过程中,需要进行内存管理,以保证高效.快速的分配内存,并且在适当的时候释放和回收内存资源. 一.Objective-C内存管理的对象 IOS开发 ...

  5. 终于明白那些年知其然而不知其所以然的iOS内存管理方式

    终于明白那些年知其然而不知其所以然的iOS内存管理方式 前言 从我开始学习iOS的时候,身边的朋友.网上的博客都告诉我iOS的内存管理是依靠引用计数的,然后说引用计数大于1则对象保存在内存的堆中而引用 ...

  6. iOS内存管理 —— 自动释放池和runloop

    iOS内存管理 -- 自动释放池和runloop 1. 自动释放池 1.1 自动释放池介绍 1.2 自动释放池底层原理 objc_autoreleasePoolPush autoreleaseNoPa ...

  7. iOS - 内存管理 01

    iOS - 内存管理 01 一.概述 内部管理简单来说就是计算机内部存储的管理,我们从冯·诺依曼结构说起,冯·诺依曼结构指出了计算机由运算器.控制器.存储器.输入和输出设备几大部件组成.拿 iPhon ...

  8. iOS 内存管理机制与原理

    内存分区 内存一般分为五大区:栈区.堆区.常量区.全局区.代码区.如图 1.栈区 是由编译器自动分配并释放的,主要用来存储局部变量.函数的参数等,是一块连续的内存区域,遵循先进后出(FILO)原则.一 ...

  9. iOS内存管理策略和实践

    来源:http://www.baidu.com/link?url=irojqCBbZKsY7b0L2EBPkuEkfJ9MQvUf8kuNWQUXkBLk5b22Jl5rjozKaJS3n78jCnS ...

最新文章

  1. C# 异步读取数据库里面的数据与绑定UI的解决办法
  2. 我在 GitHub 上看到了一个丧心病狂的开源项目!治好了我的拖延症
  3. bartender2020中文版
  4. UA OPTI501 电磁波 经典电动力学中的Fourier方法基础
  5. 硬编码学习笔记(二)—— 经典变长指令
  6. Altium Designer 的使用笔记
  7. SQLLite (一)基本介绍
  8. linux 其他参数
  9. yb3防爆电机型号含义_yb3防爆电机型号含义有哪些?
  10. [Ext JS 4] 实战之Chart, Column Chart 定制颜色
  11. MySQL · 引擎特性 · 基于InnoDB的物理复制实现(转载)
  12. [leetcode]Two Sum @ Python
  13. 人力资源管理(HR)专业书籍推荐
  14. 计算机程序设计流程图循环,流程图循环画法_流程图用什么办公软件
  15. Ventoy+WePE 装机教程(装PVE+ESXI等,不用单独费一个U盘)
  16. 北京公司买车,都需要什么手续?摇号有什么特殊要求?
  17. 钉钉 消息防撤回 分析
  18. SAPAS91导入期初固定资产数据往年购置与当年购置的区别
  19. Python 批量修改文件名称测试
  20. 【BI学习作业04-ALS算法与推荐系统】

热门文章

  1. 一句话证明:费马大定理
  2. 北京一日行之十二——植物园、蜜蜂馆、碧云寺、香山
  3. 华为平板如何换计算机的皮肤,走出护肤误区,华为镜子携手皮肤专家化解护肤难题...
  4. 《python 机器学习算法-logistics regression》
  5. Pod控制器(一)ReplicaSet
  6. springboot+乡村图书管理系统 毕业设计-附源码191505
  7. 利用C语言实现二叉搜索树的遍历、查找、插入、删除
  8. 物流领域如何利用物联网来打造智能化物流体系
  9. matlab仿真plant函数,(整理)matlab预测控制工具箱函数.
  10. 单片机介绍与内部结构