ObjectiveC 内存管理

内存的五大区域

  • 栈:局部变量 (当局部变量的作用域被执行完毕之后,这个局部变量就会被系统立即回收);
  • 堆:OC对象和使用C函数申请的空间;
  • BSS段:未初始化的全局变量、静态变量,一旦初始化就回收并转存到数据段之中;
  • 数据段:已经初始化的全局变量、静态变量,直到程序结束的时候才会被回收;
  • 代码段:二进制代码,程序结束的时候,系统会自动回收存储在代码段中的数据.

        栈、BSS段、数据段、代码段存储在它们中的数据的回收,是由系统自动完成的,不需要我们干预。存储在堆中的OC对象,系统不会自动回收,直到程序结束的时候才会被回收。因此,内存管理的范围是存储在堆中的0C对象。

引用计数器

定义

  1. 每个对象都有个属性,叫做retainCount,即引用计数器,类型是unsigned long 占据8个字节.引用计数器的作用:用来记录当前这个对象有多少个人在使用它。默认情况下,创建1个对象出来这个对象的引用计数器的默认值是1。
  2. 当多1个人使用这个对象的时候。应该先让这个对象的引用计数器的值+1 ,代表这个对象多1个人使用。
  3. 这个对象少1个人使用的时候。应该先让这个对象的引用计数器的值-1 ,代表这个对象少1个人使用。
  4. 当这个对象的引用计数器变为0的时候,代表这个对象无人使用。这个时候系统就会自动回收这个对象。

如何操作引用计数器

  1. 为对象发送1条retain消息,对象的引用计数器就会加1,当多1个人使用对象的时候才发;
  2. 为对象发送1条release消息,对象的引用计数器就会减1,当少1个人使用对象的时候才发;
  3. 为对象发送1条retainCount消息,就可以取到对象的引用计数器的值;
  4. 在对象被回收的时候,会自动调用对象的dealloc方法.

        重写dealloc方法的规范:必须要调用父类的dealloc方法,并且要放在最后一句代码。

[super dealloc];

内存管理的分类

  • MRC: Manual Reference Counting 手动引用计数
  • -------------------i0S5-------------------------
  • ARC: Automatic Reference Counting 自动引用计数

内存管理的原则

  • 有对象的创建,就要匹配1个release;

  • retain的次数和release的次数要匹配;
  • 谁用谁retain,谁不用谁release 。

回收对象的本质

        申请1个变量,实际上就是向系统申请指定字节数的空间,这些空间系统就不会再分配给别人了, 当变量被回收的时候,代表变量占用的字节空间从此以后系统可以分配给别人使用了,但是字节空间中存储的数据还在。

成员变量的setter方法

- (void)setCar:(Car *)car
{if(_car!=car)// 旧对象不是同一个对象{[_car release];// release旧对象_car = [car release];// retain新对象}
}

@property

@property的作用

  1. 简化代码@property 自动生成实例变量的声明,以及对应的 Getter 和 Setter 方法,避免繁琐的手动编写。

  2. 定义属性的访问控制:通过各种修饰符,可以控制属性的访问方式(如读写权限、内存管理语义等)

@property的参数

  • nonatomic atomic:默认是atomic,是线程安全的,但效率低,建议atomic;
  • retain assign:默认值是assign,生成的setter方法的视线就是直接赋值;retain的setter方法实现就是标准的MRC内存管理代码;当属性的类型是OC对象时,就使用retain,非OC对象使用assign;但是reatin并不会在dealloc中生成release的代码,我们需要手动写;
  • readwrite readonly:前者同时生成getter、setter,后者只会生成setter;

@class

        当两个类相互包含的时候,如Person.h中包含Book.h 而Book.h中又包含Person.h。这个时候,就会循环引用,就会造成无限递归的问题,而导致无法编译通过。

        解决方法:其中一边不要使用#import引入对方的头文件,而是使用@class+类名来标注这是1个类。这样子就可以在不引入对方头文件的情况下,告诉编译器这是1个类。

@cLass与#import的区别

  1. #import是将指定的文件的内容拷贝到写指令的地方。
  2. @class 并不会拷贝任何内容。只是告诉编译器,这是1个类,这样编译器在编译的时候才可以知道这是1个类。

对象相互引用

        A对象的属性是B对象,B对象的属性是A对象。这个时候如果两边都使用retain 那么就会发生内存泄露。解决方案:1端使用retain 另外1端使用assign,使用assign的那1端在dealloc中不再需要release了。

自动释放池

原理

        存入到自动释放池中的对象,在自动释放池被销毁的时候。会自动调用存储在该自动释放池中的所有对象的release方法。

        可以解决的问题:将创建的对象,存入到自动释放池之中,就不再需要手动的relase这个对象了。

创建自动释放池

@autoreleasepool
{}

将对象存储到自动释放池

  1. 在自动释放池之中调用对象的autorelease方法,就会将这个对象存入到当前自动释放池之中;
  2. 这个autorealse方法返回的是对象本身,所以我们可以这么写:
@autoreleasepool
{Preson *p=[[[Person alloc] init]autorelease];
}

        此时当自动释放池执行完毕之后就会立即为自动释放池里的对象发送一条release方法。(只是省略创建对象匹配的release) 。

注意事项

  • 内存占用大的对象不要随意使用autorelease,害怕大对象释放较晚导致内存持续不降;
  • 内存小的对象安心使用。

类方法规范

  1. 一般情况下,要求提供与自定义构造方法相同功能的类方法.这样可以快速的创建1个对象;
  2. 使用类方法创建的对象,要求这个对象在方法中就已经被autorelease过了。这样,我们只要在自动释放池中,调用类方法来创建对象,那么创建的对象就会被自动的加入到自动释放中。
  3. 如果没有参数就直接是类名 如果有参数就是 类名withXX:
+ (instancetype) person
{
return [[[self alloc] init autoreleasel;
}

        这样,我们直接调用类方法就可以得到1个已经被autorelease过的对象。       

@autoreleasepool
{
Person *p1 = [Person person];
//这个p1对象已经被autorelase过了.不需要再调用autorelase
1/这个p1对象就被存储到当前自动释放池之中,
}//当自动释放池结束.就会为存储在其中的p1对象发送release消息

 ARC

        当ARC开启时,编译器会自动的在合适的地方插入retain、release、autorelase代码。编译器自动为对象做引用计数,而作为开发者,完全不需要担心编译器会做错(除非开发者自己错用了ARC)。另外,在dealloc中,不允许[super dealloc]。

ARC机制下,对象何时被释放?

  • 本质:对象的引用计数器为0的时候,自动释放;
  • 表象:只要没有强指针指向这个对象,这个对象就会立即回收;

强指针与弱指针

强指针:默认情况下,我们声明1个指针就是1个强指针。也可以使用_strong来显示的声明这是1个强指针.

  • Person *p1;这是1个强指针,指针默认情况下都是1个强指针。
  • _strong Person *p2;这也是1个强指针.使用_strong来显示的声明强指针。

弱指针:使用_weak标识的指针就叫做弱指针.

无论是强指针还是弱指针,都是指针,都可以用来存储地址,这1点没有任何区别。都可以通过这个指针访问对象的成员。唯一的区别就是在ARC模式下,他们用来作为回收对象的基准。

但是不能创建一个用弱指针存储某个对象,因为该对象刚刚创建出来就会被释放。

单个对象的内存管理

在ARC的机制下:当1个对象没有任何的强指针指向它的时候,这个对象就会被立即回收。

1)当指向对象的所有的强指针被回收的时候,对象就会被立即回收。

int main(int argc, const char * argv[]){@autoreleasepool{Person *p1 = [Person new];//p1是1个强指针.Person *p2 = P1;//p2也是个强指针.P1和p2都指向Person对象.//每1个指针变量默认情况下都是1个强指针变量;}//当执行到这里的时候。P1指针被回收,p2指针也被回收。那么Person对象就没有任何//强指针指向它了,对象就在这被回收.return 0;}

2)将所有指向对象的强指针赋值为nil的时候,对象就会被立即回收.

int main(int argc, const char * argvll)@autoreleasepool{Person *p1 = [Person new] ;//p1是1个强指针,//因为我们说过,每1个指针变量默认情况下都是1个强指针变量。P1 = nil;//当执行到这句话的时候.p1赋值为nil.//p1指针不再执行Person对象.//Person对象没有被任何的指针所指向,所以Person对象在这里被释放.}return 0;}

使用建议

1)在ARC机制下.如果属性的类型是OC对象类型的.绝大多数场景下使用strong;

2)在ARC机制下.如果属性的类型不是OC对象类型的,使用assign;

3)strong和weak都是应用在属性的类型是OC对象的时候.属性的类型不是OC对象的时候就使用assign。

强指针相互引用--将一个改为weak

程序使用ARC,但有的类是MRC.使用-fno-objc-arc编译这些类

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/46391.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

STO SS1 SS2 SLS 安全释义

变频器集成安全功能已经越来越普遍,本篇介绍一下常用的一些安全功能。 安全停止变频器的功能:安全扭矩断关断(STO)、安全停机 1 (SS1)、安全停机 2 (SS2)、安全操作停止(SOS) 用于安全监控驱动运动的功能:安全限速 (SLS)、安全速度监控 (SSM) 1、安全扭矩关断 (STO) S…

uniapp踩坑小伎俩记录

1. 页面路径和文件名大小写问题 // 假设你有一个页面路径是 /pages/Home/index this.$router.push(/pages/home/index); // 小写的 home 会导致找不到页面2. 小程序平台差异 // 微信小程序中使用 uni.getSystemInfo({success: (res) > {console.log(res);} }); // 支付宝小…

原创音乐小程序的设计

管理员账户功能包括:系统首页,个人中心,用户管理,歌曲类型管理,歌曲信息管理,热门歌手管理,音乐资讯管理,系统管理 微信端账号功能包括:系统首页,歌曲信息&a…

数学建模·Topsis优劣解距离法

Topsis优劣解 一种新的评价方法,特点就是利用原有数据,客观性强。 相较于模糊评价和层次评价 更加客观,充分利用原有数据,精确反映方案差距 基本原理 离最优解最近,离最劣解越远 具体步骤 正向化 代码与原理与熵权…

链接追踪系列-08.mac m1安装logstash-番外

下载地址:https://elasticsearch.cn/download/ 配置es相关: #安装plugin: jelexbogon bin % ./logstash-plugin install logstash-codec-json_lines启动:指定配置文件运行 jelexbogon bin % nohup ./logstash -f ../config…

SSM学习7:SpringMVC简介、SpringMVC入门案例、SpringMVC bean加载控制

SpringMVC简介 Spring MVC 是 Spring 框架的一部分,它是一个用于构建 Web 应用程序的模型-视图-控制器(Model-View-Controller,MVC)框架。Spring MVC 提供了一种清晰的方式来分离业务逻辑、用户界面和控制流程,使得应…

leetcode 513. 找树左下角的值

给定一个二叉树的 根节点 root&#xff0c;请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。 示例 1: 输入: root [2,1,3] 输出: 1示例 2: 输入: [1,2,3,4,null,5,6,null,null,7] 输出: 7提示: 二叉树的节点个数的范围是 [1,104]-231 < Node.val &…

Go语言指针及不支持语法汇总

本文为Go语言中指针定义和示例及不支持语法汇总。 目录 指针 定义指针 关键字new定义 函数返回指针 空指针 Go不支持语法汇总 总结 指针 Go语言也有指针&#xff0c;结构体成员调用时&#xff0c;obj.name Go语言在使用指针时&#xff0c;会使用内容的垃圾回收机制&am…

线程池操作数据库存在线程安全问题

目录 1、前言 2、问题 3、解决方法 3.1、方法一&#xff1a;数据库约束 3.2、方法二&#xff1a;使用锁进行线程的约束 4、总结 1、前言 当前需求为&#xff1a;处理数据&#xff0c;将数据存储到数据库中&#xff0c;在存储的过程中&#xff0c;会先查询该数据是否已经存…

Hadoop数仓中常用端口详解:(第36天)

前言 在数仓&#xff08;数据仓库&#xff09;开发中&#xff0c;不同的组件和服务会使用不同的端口号进行通信。由于数仓的实现可能依赖于多种技术和框架&#xff08;如Hadoop、Hive、HBase、Spark等&#xff09;&#xff0c;因此涉及的端口号也会有所不同。以下是一些数仓开…

node.js的安装及学习(node/nvm/npm的区别)

一、什么是node、nvm和npm 1.Node.js node.js 一种Javascript编程语言的运行环境&#xff0c;能够使得javascript能够脱离浏览器运行。以前js只能在浏览器&#xff08;也就是客户端&#xff09;上运行&#xff0c;node.js将浏览器中的javascript运行环境进行封装的&#xff0c;…

张雪峰高考志愿填报

描述 张雪峰&#xff0c;一个富有才华的老师&#xff01; 对于大家的学习有不可多得的帮助。 内容 目前主要的内容以自愿填报为主&#xff0c;对于学习自愿填报有比较大的帮助&#xff01; 但是网络上面错综复杂&#xff0c;很多老旧的版本影响学习&#xff01; 而这里我整…

vue3 快速入门 (一) : 环境配置与搭建

1. 本文环境 Vue版本 : 3.4.29Node.js版本 : v20.15.0系统 : Windows11 64位IDE : VsCode 2. 安装Node.Js 首先&#xff0c;我们需要安装Node.Js。Node.js提供了运行 JavaScript 代码的环境。并且Node.js 带来了 npm&#xff0c;它是JavaScript世界的包管理工具。开发vue时&…

使用Copilot 高效开发繁忙的一天

在现代软件开发的世界里&#xff0c;使用AI工具如GitHub Copilot可以显著提高开发效率。 早晨&#xff1a;规划与启动 7:00 AM - 起床与准备 开发者早早起床&#xff0c;享用健康的早餐&#xff0c;并浏览新闻和技术博客&#xff0c;了解最新的科技动态。快速整理思路&#x…

设计模式使用场景实现示例及优缺点(行为型模式——责任链模式)

责任链模式&#xff08;Chain of Responsibility Pattern&#xff09; 责任链模式是一种行为设计模式&#xff0c;允许对象将请求沿着处理器链传递&#xff0c;直到一个处理器决定处理该请求为止。这种模式的核心在于解耦发送者和接收者之间的关系&#xff0c;通过多个对象共同…

MICS2024|少样本学习、多模态技术以及大语言模型在医学图像处理领域的研究进展|24-07-14

小罗碎碎念 本期推文主题 今天的会议很多主题都集中在大模型、多模态这两个方面&#xff0c;很明显&#xff0c;这两个方向都是目前的研究热点。 所以&#xff0c;我这一期推文会先简单的分析一下秦文健&#xff08;中科院&#xff09;和史淼晶&#xff08;同济大学&#xff09…

解释方法重载和方法重写的区别。然后,给出一个简单的递归方法实例。

方法重载&#xff08;Overloading&#xff09;与方法重写&#xff08;Overriding&#xff09;的区别 在Java编程中&#xff0c;方法重载和方法重写是两个非常重要的概念&#xff0c;它们分别体现了面向对象编程中的多态性&#xff08;Polymorphism&#xff09;的不同方面&…

【STM32开发笔记】搭建VSCode+PyOCD的STM32开发环境

【STM32开发笔记】搭建VSCodePyOCD的STM32开发环境 一、安装软件1.1 安装STM32CubeMX1.2 安装VSCode1.3 安装Arm GNU Toolchain1.4 安装Make for Windows1.5 安装Python1.6 安装PyOCD 二、安装插件2.1 VSCode插件2.2 PyOCD支持包 三、创建项目3.1 创建STM32CubeMX项目3.2 查阅原…

Spring常见问题一:IOC和DI

IOC和DI IOC和DI之间到底是什么关系&#xff1f; 什么是依赖关系&#xff1f;依赖关系会带来什么问题&#xff1f;Spring是怎么来支持依赖注入的&#xff1f; 引言 在现代软件开发中&#xff0c;面向对象编程&#xff08;OOP&#xff09;已经成为主流编程范式。然而&#xff0…

口袋算法的示例

原理 口袋算法是感知器(Perceptron)算法的一种改进。感知器算法是一种线性分类算法,但在训练数据不是线性可分的情况下,它可能无法收敛,即无法找到一个线性分类器来正确分类所有的训练样本。为了解决这个问题,口袋算法引入了一个"口袋"(Pocket),用来存储迄…