内存管理(二) - MRC关键字解读

​[DRAM Test]Intel MRC(Memory Reference Code) Memory Reference Code 阅读详情

本篇主要学习以下几个知识点

  1. alloc/reatin/release/dealloc 理解
  2. autorelease 理解
  3. autorelease GUN 实现
  4. autorelease 苹果 实现

原文地址

alloc/reatin/release/dealloc 实现


我们来看看 GUNstep 源代码中 NSObject 类的的 alloc 类方法。

id obj = [NSObject alloc];

上述调用 NSObject 类的 alloc 类方法在 NSObjecr.m 源代码中的实现如下。

+ (id) alloc
{
   return [self allocWithZone: NSDefaultMallocZone()]; 
}
+ (id) allocWithZone:(NSZone *)z
{
    return NSAllocateObject(self,0,z);
}

通过 allocWithZone: 类方法调用 N\NSAllocateObject 函数分配对象。下面我们查看 NSAllocateObject 函数.

struct obj_layout {
    NSUInterger  retained;
}
inline id NSAllocateObject (Class aClass, NSUInterger extraBytes, NSZone *zone) {

    int size = 计算容纳对象所需内存大小;
    id new = NSZoneMalloc(zone, size);
    memset(new, 0, size);
    new = (id)&((struct obj_layout *) new)[1];
}

NSAllocateObject 函数通过调用 NSZoneMalloc 函数来分配存放对象所需的内存空间,之后将改内存空间置0,最后返回作为对象而使用的指针。

image

以下是去掉 NSZone 后简化了源代码:

struct obj_layout {
    NSUInterger  retained;
}
+ (id) alloc {
    int size = sizeof(struct obj_layout) + 对象大小;
    struct obj_layout *p = (struct obj_layout *)calloc(1, size);
    return (id)(p+1);
}

alloc 类方法用 struct obj_layout 中的 retained 整数来保存引用计数,并将其写入对象内存头部,该对象内存全部置0后返回。

以下用图来展示有关 GUNstep 的实现,alloc类方法返回对象,如图

image

对象的引用计数可通过 retainCount 实例方法来取得。

id obj = [NSObject alloc];
NSLog(@"retainCount=%d", [obj retainCount]); // => 1

执行alloc后对象的 retainCount 是 “1”。下面通过 GUNstep 的源代码来确认。

- (NSUInteger)retainCount {
   return NSExtraRefCount(self) + 1; 
}
inline NSUInterger NSExtraRefCount(id  anObject) {
    return ((struct obj_layout *) anObject)[-1].retained;
}

由对象寻址找到对象内存头部,从而访问其中的retained变量。如图:

image

autorelease


autorelease 就是自动释放。这看上去很像ARC,但实际上它更类似于C语言中的自动变量(局部变量)的特性。

{
    int a;
}
/*
 因为超出变量作用域,自动变量 "int a" 被废弃,不可再访问
*/

autorelease 会像 C 语言的自动变量那样来对待对象实例。当超出其作用域(相当于变量作用域)时,对象实例的 release 实例方法被调用。另外,同 C 语言的自动变量不同的是,编程人员可以设定变量的作用域。

autorelease 的具体使用方法如下:

  1. 生成并持有 NSAutoreleasePool 对象
  2. 调用已分配对象的 autorelease 实例方法
  3. 废弃 NSAutoreleasePood 对象

NSAutoreleasePool 对象的生命周期

NSAutoreleasePool 对象的声明周期相当于 C 语言变量的作用域。对于所有调用过 autorelease 实例方法的对象,在废弃 NSAutoreleasePool 对象时,都将调用 release 实例方法。如上图。

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

id obj = [[NSObject alloc] init];

[obj autorelease];

[pool drain];

“[pool drain]” 等同于 “[obj release]”。

在 Cocoa 框架中,相当于程序主循环的 NSRunLoop 或者在其他程序可运行的地方,对 NSAutoreleasePool 对象进行生成、持有和废弃处理。因此,应用程序开发者不一定非得使用 NSAutoreleasePool 对象来进行开发工作。

意思就是我们不一定需要去管理 NSAutoreleasePool。

NSRunLoop

尽管如此,但在大量产生 autorelease 的对象时,只要不废弃 NSAutoreleasePool 对象,那么生成的对象就不能被释放,因此有时会产生内存不足的现象。

典型的例子:读入大量图像的同时改变尺寸。图像文件读入到 NSData 对象,并从中生成 UIImage 对象,改变该对象尺寸后生成新的 UIImage 对象。这种情况下,就会大量生成 autorelease 对象。

for (int i = 0; i < 图像数; ++i){
    /*
    读入图像
    大量产生 autorelease 对象
    由于没有废弃 NSAutoreleasePool 对象
    最终导致内存不足
    */
}

在此情况下,有必要在适当的地方生成,持有或者废弃 NSAutoreleasePool 对象。

for (int i = 0; i < 图像数; ++i){

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    /*
    读入图像
    大量产生 autorelease 对象
    */

    [pool drain];
}

另外,Cocoa 框架中也有很多类方法用于返回 autorelease 的对象。比如 NSMutableArray 类的 arrayWithCapacity 类方法。

id array = [NSMutableArray arrayWithCapacity:1];

此源代码等同于以下源代码

id array = [[[NSMutableArray alloc] initWithCapacity:1] autorelease];

autorelease 实现 - GUNstep是如何实现的


[obj autorelease];

此源代码调用 NSObject 类的 autorelease 实例方法。

GUNstep实现:

- (id) autorelease {
    [NSAutoreleasePool addObject:self];
}

autorelease 实例方法的本质就是调用 NSAutoreleasePool 对象的 addObject 类方法。

NSAutoreleasePool专栏

+ (void) addObject:(id)anObj {

    NSAutoreleasePool *pool = 取得正在使用的 NSAutoreleasePool 对象;

    if (pool != nil) {
        [pool addObject: anObjc];
    }else{
        NSLog(@"NSAutoreleasePool 对象非存在状态下调用 autorelease")
    }
}

addObject 类方法调用正在使用的 NSAutoreleasePool 对象的 addObject 实例方法。

如果嵌套或者持有 NSAutoreleasePool 对象,理所当然会使用最内侧的对象。

- (void) drain {
    [self dealloc];
}
- (void) dellloc {
    [self emptyPool];
    [array release];
}
- (void) emptyPool {
    for (id obj in array){
        [obj release];
    }
}

虽然调用了好几个方法,但是可以确定对于数组中的所以对象都调用了 release 实例方法。

苹果 autorelease 的实现


objc4 库的 runtime/objc-arr.mm 来确认苹果中 autorelease 的实现

Class AutoreleasePoolPage 
{
    static inline void *push (){
        相当于生成或者持有 NSAutoreleasePool 对象
    }
    static inline void *pop (void *token){
        releaseAll();
    }
    static inline id autorelease (id obj){
        相当于 NSAutoreleasePool 类的 addObject 类方法
        NSAutoreleasePoolPage *autoreleasePoolPage = 取得正在使用的实例;
        autoreleasePoolPage ->add(obj);
    }
    id *add (id obj) {
        将对象追加到内部数组中
    }
    void releaseAll(){
        调用内部数组中对象的release实例方法
    }
}
void *objc_autoreleasePoolPush(void){
    return AutoreleasePoolPage::push();
}
void *objc_autoreleasePoolPop(void *ctxt){
    return AutoreleasePoolPage::pop(ctxt);
}
id *obj_autorelease(id obj) {
    return AutoreleasePoolPage:autorelease(obj);
}

C++类中虽然有动态数组的实现,但其行为和GUNstep的实现完全相同。

我们使用调试器来观察一下NSAutoreleasePool类方法和 autorelease 方法的运行过程。如下所示,这些方法调用了关联于 objc4 库的 autorelease 实现的函数。

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
/*= objc_autoreleasePoolPush()*/

id obj = [[NSObject alloc] init];

[obj autorelease];
/*= obj_autorelease(obj)*/

[pool drain];
/*= objc_autoreleasePoolPop(pool)*/

另外,可通过 NSAutoreleasePool 类中的调试用非公开类方法 showPools 来确认已被 autorelease 的对象情况。

[NSAutoreleasePool showPools];

NSAutoreleasePool 类的 showPools 类方法只能在 iOS 中使用,作为替代,在现在的运行时系统中我们使用调试用非公开函数 _objc_autoreleasePoolPrint()。

/* 函数声明 */
extend void _objc_autoreleasePoolPrint();

/* autorelesepool 调试用输出开始*/
_objc_autoreleasePoolPrint();

如果运行此函数,就能像下面这样在控制台中来确认 AutoreleasePoolPage 类的情况。

image

NSAutoreleasePool 调用 autorelease 会如何?发生异常

通常在使用 Obejctive-C,也就是 Foundation 框架时,无论调用哪一个对象的 autorelease 实例方法,实际上调用都是 NSObject 类的 autorelease 实例方法。但是对于 NSAutoreleasePool 类,autorelease 实例方法已被该类重载,因此运行时就会报错。

全国大学校园网—拓扑图欣赏 全国大学网络拓扑图(一百张) 典型十张 1、 中央财经大学 2、国防科技大学 3、济南大学 4、西安石油大学 5、南通大学IPV6网络 6、中国矿业大学 7、青海师范大学 8、内蒙古科技大学 9、三峡大学 10、中共江苏省党校 剩余90张 点赞、评论获取 ... 阅读详情

相关推荐

gsplat在windows本地部署

3DGS的cuda提效和优化内存的版本gsplat,使得在有一定GPU计算能力的电脑上也能够尝尝3DGS的效果。我在2025年的开年之初尝试配置过gsplat,由于过程中遇到很多问题,最终还是有一些windows上字符编码的问题,没有跑通,最近看gsplat的github更新了3DGUT,优化了反射和二次折射,以及适用于非线性相机模型,如鱼眼相机等。在data目录下下载好了360_v2的数据,进入之后images文件夹是原始分辨率的图像,images_2是下采样系数为2的数据,以此类推。

yuleaf_csdn的博客 2370

内存管理(一)MRC

内存管理(一)MRC 管的谁 在Objective-C中创建的对象都分配在堆区,内存管理针对的也是这块区域。 引用计数 Objective-C内存管理的核心其实引用计数,引用计数(Reference Count)是一个简单而有效的管理对象生命周期的方式。当我们创建一个新对象的时候,它的引用计数为 1,当有一个新的指针指向这个对象时,我们将其引用计数加 1,当某个指针不再指向这个对象时,我们将其引用计数减 1,当对象的引用计数变为 0 时,说明这个对象不再被任何指针指向了,这个时候我们就可以将对象销毁,回收内

iOS随笔 3646

MT4-EA自动化交易研究笔记(2022-04-22)

自从接触到mt4的EA自动化交易,更让我这个10多年的老程序员看到了曙光,目前来看也确实出了一点成果,只是是否能稳定盈利有待时间的考验,所以开此专栏,一来做做记录与分析,更好的优化我的EA,二来也希望能与更多的高手交流,以完善我的交易系统

t35254056的博客 2291

memory reference code(MRC)与内存兼容性

在普通用户看来,0603 BIOS是个不起眼的更新,但在行业人士看来,这个是重大的更新,提升了内存兼容性。实测解决了大部分DDR4 16G 3600、DDR4 16G 4000频率内存XMP兼容性问题,对PRIME Z690-P DDR5平台也有较大改善。 什么是MRC? memory reference code(MRC)是内存初始化参考代码,它一般由CPU厂商(Intel/AMD)开发,并经过大量测试 MRC在运行的时候会读取内存条上SPD(serial presence detect)的信息..

qq1327798176的博客 1万+

Keil MDK 5.37及之后版本 安装AC5(ARMCC)编译器详细步骤

由于Keil 5.37及之后版本不再默认安装AC5(ARMCC)编译器,这就会导致由AC5编译的工程无法正常编译,往往输出窗口会提示以下信息:*** Target ‘STM32xxxx‘ uses ARM-Compiler ‘Default Compiler Version 5‘ which is not available.

s_Modesto的博客 1万+

使用MID360在室内快速定位

在预构建的点云地图中实现实时3D全球定位。通过融合FAST-LIO的低频全局定位(约0.5~0.2Hz)和高频里程计,整个系统的计算效率很高。消除里程计的累计误差初始定位可以通过RVIZ的粗略手动估计或来自另一个传感器/算法的姿势来提供。

CTwinkle的博客 1162

iOS之ARC规则

搞清楚一些名词 内存泄漏: 内存泄漏(Memory Leak)是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。 ARC 使用ARC时,引用计数其实还存在,释放和保留的操作由系统替我们完成,MRC下的 retain、release、autorelease、delloc这些方法无法调用。 ARC管理内存时不是通过普通的消息派...

wtl1804的博客 328

光模块封装工艺简介

光模块按照部件可以分为芯片、光器件、光模块三个层级;按照应用领域大概可分为电信应用、数通应用两个领域;按照内部器件的封装工艺可分为TO、Box、COB三大类。 但是,无论是哪种类型的光模块,其生产工艺基本上可以分为封装、测试两大块。   那什么叫做器件封装呢?我的理解器件封装就是利用胶水、焊料、机械、热量等手段把器件按照一定的先后次序结合形成一个整体的过程,就好像早上吃的煎饼,把面粉、鸡蛋、脆饼、烤肠、葱花等这些“器件”,按照一定的顺序,通过食用油、甜面酱、加热、卷起来等手段结合到一起,形成了美味的

qq_33253182的博客 2818

MRC系列(一)之模组及信号

本系列旨在从BIOS开发人员的角度来认识MRC&DDR training.

qq_39578202的博客 2985

动力学约束下的运动规划算法——Kinodynamic RRT*算法

动力学约束下的运动规划算法——Kinodynamic RRT*算法

慕羽★的博客 6749

Android 14.0 系统设置显示主菜单添加屏幕旋转菜单实现旋转屏幕功能

在14.0的系统rom定制化开发中,在对系统设置进行定制开发中,有产品需求要求增加 旋转屏幕功能的菜单,就是在点击旋转屏幕菜单后弹窗显示旋转0度,旋转 90度,旋转180度, 旋转270度针对不同分辨率的无重力感应的大屏设备的屏幕旋转功能的实现, 接下来就来分析实现这个功能

安卓兼职framework和app工程师的博客 1310

属性关键字

iOS属性关键字介绍

weixin_61196797的博客 911

想在 Visual Studio Code 里进行 ABAP 开发,需要安装的扩展列表

安装完毕后,我们可以将 SAP 系统配置为 Visual Studio Code 连接的远程文件系统。为了连接到 SAP 系统,需要启用 ABAP 开发工具 (ADT) ICF 节点,这与 SAP Hana Studio 等工具使用的服务相同。打开 SAP GUI 并连接到目标系统,运行事务 SICF,然后激活 ADT_SRV 服务,如下所示。这启用了允许代码编辑器和 IDE 连接到 SAP 系统的服务。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 3119

【iOS】—— 属性关键字

一.属性的含义 属性的本质就是:实例变量 + get方法 + set方法。 众多属性关键字是对自动生成的get、set方法进行了修饰。 二.属性的功能 1.给现有的成员变量生成一对setter/getter方法。 2.如果没有声明成员变量,自动声明一个_属性名的私有变量(默认成员变量是受保护的)。 三.基本属性关键字 我们常用的属性关键字有:assign,weak,unsafe_unretained,strong,retain ,copy,readonly,readwrite , nonatomic,nat

m0_55124878的博客 341

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

ARC内存管理机制详解

        ARC在OC里面个人感觉又是一个高大上的牛词,在前面Objective-C中的内存管理部分提到了ARC内存管理机制,ARC是Automatic Reference Counting---自动引用计数。有自动引用计数,那么就得有手动引用计数MRC(Mannul Reference Counting),前面已经提到过了MRC。那么在ARC模式下是不是意味着我们就可以一点也不用进行内存管...

weixin_34062469的博客 201

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

OC-精简解读 block

  网上关于block的解释已经很多了,在此,本文仅对block的精简解读。 一、block是什么?   block在OC中是对象,在运行时会被转化成函数。但是block与OC中其他对象最大的不同是:一般来说,block初始化是储存在栈区的。关于block在内存中的储存位置我们在下面的内容中探讨。因为情况是在是太多了。   block的定义: struct Block_descript...

weixin_33722405的博客 104

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

OC 基础知识梳理

一、ViewController的生命周期 二、OC的关键字 三、计算机网络层级 四、两个子视图找到同一个VC 五、判断block的类型 liu

Coding_Physical的专栏 636

ios ARC入门和使用

本文部分实例取自iOS 5 Toturail一书中关于ARC的教程和公开内容,仅用于技术交流和讨论。请不要将本文的部分或全部内容用于商用,谢谢合作。 欢迎转载本文,但是转载请注明本文出处:http://www.onevcat.com/2012/06/arc-hand-by-hand/ 本文适合人群:对iOS开发有一定基础,熟悉iOS开发中内存管理的Reference Counting机

Code-lover's Learning Notes 807

从事iOS研发6年的面经——希望对你们有帮助

前言: 今天和大家分享一下,我从事iOS开发6年的面试心得。大大小小参加过不下30+公司的面试,其中不乏BAT、TMD等一线互联网公司,总结一下,发现大厂招聘都有一个共性。 对技术的要求很全面,有些同学认为iOS掌握了基础的UI、网络、内存、多线程等等就够了,其实要想更好的应付iOS的面试,这些是远远不够的。比如对RunTime底层实现机...

weixin_34144848的博客 114

block与协议-代理

1.block类型-存储代码块的类型在异步编程时常需要进行函数回调,在C#中会用匿名委托或者lambda表达式讲一个操作作为参数进行传递. ObjC中是使用对于闭包的实现,在块状中我们可以持有或引用局部变量. 同时利用Block可以将一个操作作为参数进行传递;blcok用法: 定义:返回值类型 ( ^变量名 ) ( 形参类型 ); 赋值:变量名=^(形参){ 代码块+形参变量 }; 使用:变量

梦浮生清月夜 875

Objective-C入门指南:iOS开发基石与Swift混编实战

面向对象编程是现代软件开发的核心范式,它通过封装、继承和多态等机制组织代码。在iOS/macOS生态中,Objective-C作为C语言的超集,其独特的消息传递机制和动态运行时特性,构成了Cocoa和Cocoa Touch框架的设计哲学基础。理解Objective-C的原理,不仅能帮助开发者深入掌握内存管理、引用循环等底层机制,更能无缝对接海量存量代码库,提升解决复杂问题的能力。在实际工程中,掌握Objective-C与Swift的混编技巧,是维护大型项目、集成第三方库的关键。本文聚焦Objective-C

weixin_33881140的博客 470

100+篇技术文章推荐总有一篇你想看的

1.Class类的底层实现原理 - 链接 链接 2.Category分类的底层实现原理 - 链接 3.Block块的底层实现原理和使用 - 链接一 链接二 4.@autoreleasepool自动释放池的底层实现原理 autoreleasepool 5.KVO键值观察底层实现原理和使用 - 链接 链接 6.KVC简直编码的底层实现原理使用. 链接 7.Runtime机制的原理 链接 链接 链接...

weixin_34032792的博客 221

【iOS开发】——MRC(手动内存管理)的一些补充

iOS开发——MRC(手动内存管理)最近在复习MRC,发现当时总结的时候有几个点没有总结上,今天在写一篇补充记录一下。

weixin_51638861的博客 752

黑马程序员-[OC语言] 第三篇:MRC手动内存管理总结

OC加强--第六天学习总结: 1. 内存管理范围:  1)管理任何继承NSObject 的对象,对其他的基本数据类型无效。 2. OC内存管理的原理 1)引用计数器的作用:引用计数器是判断对象要不要回收的依据(存在一种例外:对象值为nil 时,引用计数器为0 不回收空间)就是计数器是否为0,若为0 则不存在。 2)引用计数器的操作; 给对象发送消息,进行相应的计数器操作; retai

csdn_llj的博客 538

iOS开发——MRC(手动内存管理)

iOS开发——MRC(手动内存管理)内存分配区域栈区堆区总结常量区总结代码区总结全局区关于如何查看一个对象在堆区 / 栈区 我们要想了解内存管理的知识前,必须先搞明白计算机的内存分配以及计算机是如何处理内存的。 内存分配区域 内存指的就是RAM(random access memory),内存分配区域主要分为五个区:栈区(系统管理的地方)、堆区(程序员控制的地方)、静态区(全局区)、常量区、代码区。 栈区 栈区(stack)由编译器自动分配并释放,存放的是函数的参数值,局部变量,基本类型的变量和对象引用类型

weixin_51638861的博客 1693

iOS ------ MRC

这里只是发送release消息,如果当时的引用计数依旧不为0,则对象依然不会被释放,autorelease方法返回对象本身,且调用完autorelease方法后,对象的计数器不变。如果将新值直接赋给实例变量,而没有堆旧值进行适当的释放操作,旧值的引用计数就从不会减少,对象的内存也不会释放,这就会导致内存泄漏。当一个对象被复制给一个实例变量,为了确保对象在使用时保持有效,需要增加对象的引用计,这样可以保证在其他地方意外释放对象。时,开发者只需要关注对象的强引用和弱引用,无需关心对象的引用计数。

m0_73974056的博客 1111
上一篇: React Native - (二) Props属性和State状态
下一篇: 内存管理(四) - 源码解读所有权修饰符(一)
Code_浅蓝
博客等级 码龄11年 28粉丝 42原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值