IOS 内存管理

iPhone内存管理 详细且全面地讲述了iPhone开发中的内存管理技术 立即下载

小议iphone内存管理与属性

 

一、前言

      对于大多数从C++或者JAVA转过来学习Object-C(以下简称OC)的人来说,OC这门语言看起来非常奇怪,用起来也有点麻烦。

      OC没有像JAVA一样的垃圾回收机制,也就是说,OC编程需要程序员手动去管理内存。这就是为什么它烦的原因,苹果却一直推崇开发者在有限硬件资源内写出最优化的代码,使用CPU最少,占用内存最小。

 

二、基本原理

对象的创建:

      OC在创建对象时,不会直接返回该对象,而是返回一个指向对象的指针,因此出来基本类型以外,我们在OC中基本上都在使用指针。

      ClassA  *a = [[ClassA   alloc]  init];

      在[ClassA   alloc]的时候,已经发送消息通知系统给ClassA的对象分配内存空间,并且返回了指向未初始化的对象的一个指针。

      未初始化的ClassA对象接手到init消息,init返回指向已初始化后的ClassA对象的一个指针,然后将其赋值给变量a。

在创建并使用完一个对象的时候,用户需要手动地去释放该对象。

      [a   dealloc];

如果指针a和b同时指向堆中同一块内存地址

      ClassA  *a = [[ClassA   alloc]  init];

      ClassA  *b = a;

      [a   dealloc];

当执行到第三行的时候,指针b就成了无头指针。这是一个在C++中也是常见的错误,我们需要避免这类错误,因为无头指针是危险的。

引用计数:

      OC在内存管理上采用了引用计数(retain count),在对象内部保存一个数字,用来表示被引用的次数。init、new和copy都会让retain count加1。当销毁对象的时候,系统不会直接调用dealloc方法,而是先调用release,让retain count 减1,当retain count等于0的时候,系统才会调用dealloc方法来销毁对象。

      在指针赋值的时候,retain count 是不会自动增加的,为了避免上面所说的错误,我们需要在赋值的时候手动retain一次,让retain count 增加1。

      ClassA  *a = [[ClassA   alloc]  init];  // retain count = 1

      ClassA  *b = a;

      [b   retain];  // retain count = 2

      [a   dealloc];

这样在执行到第四行的时候,对象的retain count只是减了1,并没有被销毁,指针b仍然有效。

 

内存泄露:

      就如上面列子所示,当生成ClassA对象时,指针a拥有对该对象的访问权。如果失去了对一个对象的访问权,而又没有将retain count减至0,就会造成内存泄露。也就是说,分配出去的内存无法回收。

      ClassA  *a = [[ClassA   alloc]  init];

      a  =  nil;

 

三、Autorelease Pool

      为了方便程序员管理内存,苹果在OC中引入了自动释放池(Autorelease Pool)。在遵守一些规则的情况下,可以自动释放对象。但即使有这么一个工具,OC的内存仍需要程序员时刻关注(这个自动释放池跟JAVA的垃圾回收机制不是一回事,或者说,骑马都追不上JAVA的机制,可能连尘都吃不到)。

      ClassA  *a = [[[ClassA   alloc]  init]  autorelease];

      //retain count = 1,但无需release

Autorelease Pool 的原理:

      autorelease pool 全名叫做NSAutoreleasePool,是OC中的一个类。autorelease pool并不是天生就有的,你需要手动的去创建它

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

一般地,在新建一个iphone 项目的时候,xcode会自动地为你创建一个autorelease pool,这个pool就写在Main函数里面。

在NSAutoreleasePool中包含了一个 可变数组,用来存储被声明为autorelease的对象。当NSAutoreleasePool自身被销毁的时候,它会遍历这个数组,release数组中的每一个成员(注意,这里只是release,并没有直接销毁对象)。若成员的retain count 大于1,那么对象没有被销毁,造成内存泄露。

      默认的NSAutoreleasePool 只有一个,你可以在你的程序中创建NSAutoreleasePool,被标记为autorelease的对象会跟最近的NSAutoreleasePool 匹配。     NSAutoreleasePool  *pool = [[NSAutoreleasePool  alloc]  init];

      //Create some objects

      //do something…

      [pool  release];

你也可以嵌套使用NSAutoreleasePool  ,就像你嵌套使用for一样。

      即使NSAutoreleasePool  看起来没有手动release那么繁琐,但是使用NSAutoreleasePool  来管理内存的方法还是不推荐的。因为在一个NSAutoreleasePool  里面,如果有大量对象被标记为autorelease,在程序运行的时候,内存会剧增,直到NSAutoreleasePool   被销毁的时候才会释放。如果其中的对象足够的多,在运行过程中你可能会收到系统的低内存警告,或者直接crash。

 

Autorelease Pool   扩展:

      如果你极具好奇心,把Main函数中的NSAutoreleasePool  代码删除掉,然后再自己的代码中把对象声明为autorelease,你会 发现系统并不会给你发出错误信息或者警告。用内存检测工具去检测内存的话,你可能会惊奇的发现你的对象仍然被销毁了。

      其实在新生成一个Run Loop的时候,系统会自动的创建一个NSAutoreleasePool  ,这个NSAutoreleasePool 无法被删除。

 

      在做内存测试的时候,请不要用NSString。OC对字符串作了特殊处理

      NSString  *str  =[ [NSString alloc]  stringWithString:@”123”];

在输出str的retain count 的时候,你会发现retain count 大于1。

 

四、手动管理内存

      使用alloc、new、copy创建一个对象,该对象的retain count 都等于1,需要用release来释放该对象。谁创建,谁去释放。在这3钟方法以外的方法创建的对象,都被系统默认的声明为autorelease。

      ClassA  *a = [[ClassA   alloc]  init];

      ClassA  *b = a;

      [b   retain];

      //do smoething

      [b release];

      b  =  nil;

把一个指针赋值给另外一个指针的时候,a 指针所指向的对象的引用次数并没有增加,也就是说,对象的retain count依然等于1。只有在retain了之后,retain count 才会加1。那么,如果这时候执行[a  release],只是a指针放弃了对对象的访问权,对象的retain count 减1,对象没有被销毁。只有当b也执行了release方法之后,才会将对象销毁掉。因此,谁retain了,谁就要release。

      在对象被销毁之后,指针依然是存在的。所以在release了之后,最好把指针赋为空,防止无头指针的出现。顺便一说,release一个空指针是合法的,但是不会发生任何事情。

      如果你在一个函数中创建并返回一个对象,那么你需要把这个对象声明为autorelease

      (ClassA  *)Function()

      {

           ClassA *a = [[[ClassA   alloc]  init]  autorelease];

           return a;

      }

不这样做的话,会造成内存泄露。

 

五、属性与内存管理

      苹果一直没有强调的一点是,关于属性中的retain。事实上,属性中带有retain的,在赋值的时候可能已经在合成的setter中retain了一次,因此,这里也需要release。

      @property实际上是getter和setter,@synthesize是合成这2个方法。为什么在声明了属性之后可以用“.”来直接调用成员变量呢?那是因为声明属性以后系统根据你给的属性合成了一个set方法和一个get方法。使用“.”与属性并没有直接关联,如果你不嫌麻烦,在你的程序里面多写一个set和get方法,你也可以使用“.”来调用变量。

      @property(),如果你里面什么都不写,那么系统会默认的把你的属性设置为:

      @property(atomic, assign)…..

关于nonatomic:

      这个属性没有对应的atomic关键字,即使我上面是这么写,但atomic只是在你没有声明这个特性的时候系统默认,你无法主动去声明这一特性。

      如果你的程序只有一个主线程,或者你确定你的程序不会在2个或者以上线程运作的时候访问同一个变量,那么你可以声明为nonatomic。指定nonatomic特性,编译器合成访问器的时候不会去考虑线程安全问题。如果你的多个线程在同一时间会访问到这个变量的话,可以将特性声明为atomic(通过省略关键字nonatomic)。在这种特性的状态下,编辑器在合成访问器的时候就会在访问器里面加一个锁(@synchronized),在同一时间只能有一个线程访问该变量。

      但是使用锁是需要付出代价的,一个声明为atomic的属性,在设置和获取这个变量的时候都要比声明为nonatomic的慢。所以如果你不打算编写多线程代码,最好把变量的属性特性声明为nonatomic。

关于assign、retain和copy:

      assign是系统默认的属性特性,它几乎适用于OC的所有变量类型。对于非对象类型的变量,assign是唯一可选的 特性。但是如果你在引用计数下给一个对象类型的变量声明为assign,那么你会在编译的时候收到一条来自编译器的警告。因为assign对于在引用计数下的对象特性,只创建了一个弱引用(也就是平时说的浅复制)。这样使用变量会很危险。当你release了前一个对象的时候,被赋值的对象指针就成了无头指针了。因此在为对象类型的变量声明属性的时候,尽量少(或者不要)使用assign。

      关于assign合成的setter,看起来是这样的:

      -(void)setObjA:(ClassA  *)a

      {

           objA  =  a;

      }

 

      在深入retain之前,先把声明为retain特性的setter写出来:

      -(void)setObjA:(ClassA  *)a

{

           If(objA != a)

{

   [objA  release];

   objA  =  a;

   [objA  retain];  //对象的retain count 加1

}

}

明显的,在retain的setter中,变量retain了一次,那么,即使你在程序中

      self.objA  =  a;

只写了这么一句,objA仍然需要release,才能保证对象的retain count 是正确的。但是如果你的代码

      objA  =  a;

只写了这么一句,那么这里只是进行了一次浅复制,对象的retain count 并没有增加,因此这样写的话,你不需要在后面release objA。

      这2句话的区别是,第一句使用了编译器生成的setter来设置objA的值,而第二句只是一个简单的指针赋值。

 

      copy的setter看起来是这样的:

 

      -(void)setObjA:(ClassA  *)a

{

  ClassA  * temp  =  objA;

  objA  =  [a   copyWithZone:nil];

  [temp  release];

}

复制必须通过实现copyWithZone:这个方法,因次copy这个特性只适用于拥有这个方法的类型,也就是说,必须这个类支持复制。复制是把原来的对象release掉,然后让指针指向一个新的对象的副本。因此即使在setter里面release了原来的对象,你仍然需要在后面release新指向的对象(副本)。

 

 

六、尾声

      IOS开发现在唯一能用的内存管理方式就是引用计数,无论你喜欢还是不喜欢。在一个内存紧缺的机器上,你编写程序的时候也只能步步为营,尽可能的让你的程序腾出内存空间,并保证系统不会给你一个警告。即使苹果在Mac OS X 雪豹(v10.5)系统里面添加了另外一种内存管理方式(垃圾收集),但目前不适用于IOS。

 

出处:http://www.cnblogs.com/ET-Union/archive/2011/08/17/2143774.html

用VFP计算 CRC-16 Modbus 校验位 1. Modbus是一种串行通信协议,最初由Modicon(目前属于施耐德电气公司)于1979年开发2. Modbus协议是应用在Modicon产品上的,后来才被移植到其他产品上3. Modbus协议的通信接口可以有多种选择,如RS232、RS485、以太网等。 阅读详情

相关推荐

数学:箭头符号→(to)都表示什么意义?

数学符号“→”在不同领域有不同含义:在逻辑中表示“蕴含”(p→q);在函数中表示映射关系(f:A→B);在极限中表示变量趋近(x→a);在推导过程中表示推理方向(A→B)。此外,它也可能用于向量表示或数列趋势。其具体含义需结合上下文判断,核心应用场景包括逻辑运算、函数定义、极限分析和数学推导等。

shunzi2016的博客 5573

IOS 内存管理

IOS 内存管理 小议iphone内存管理与属性 一、前言 对于大多数从C++或者JAVA转过来学习Object-C(以下简称OC)的人来说,OC这门语言看起来非常奇怪,用起来也有点麻烦。 OC没有像JAVA一样的垃圾回收机制,也就是说,OC编程需要程序员手动去管理内存。这就是为什么它烦的原因,苹果却一直推...

weixin_30532369的博客 162

西门子840D新建项目

1、需要一个32位的WIN7或者XP系统,并且已经在系统中安装完成西门子840Dsl开发包和VS2008。(我采用的是XP系统虚拟机) 2、在开始->所有程序找到如下位置 3、在这个位置打开Visual Studio 4、文件->新建->项目 名称和位置都可以随意更改,点击确定。 5、在左侧选择第二个选项进入下面的界面 点击“Add Screen”按钮 可以修改“class name”然后点击“OK”返回上一个界面,再点击“Add Form” 可以修...

qq_36987047的博客 1861

Objective-C 内存管理

前言前两篇中Objective-C属性,在定义属性时我们使用一系列关键字,比如:retain,release,assgin,copy,strong,weak等等,那么这些关键字到底在程序运行起什么作用呢?下面我们通过内存管理来深刻的理解这些词的具体作用。介绍内存管理:程序在运行过程中,会创建很多的类和对象,而创建类和对象就要占用内存空间,基本类型都是系统自动管理放在栈区,而创建的类和对象放在堆区,我

yanshi_hu的博客 435

KUKA机器人自动回原点程序

创建两个全局变量分别用于储存机器人的笛卡尔姿态与关节角姿态。打开System文件夹中的config文件创建全局变量的点位。在USER GROBALS用户自定义变量Userdefined variables下创建一个E6POS类型的点位,一个E6AXIS类型的点位。

A567852的博客 5213

IEEE Transactions on Industrial Informatics(TII) 投稿须知- Initial Submission

请注意,您可以在作者中心查看稿件的当前状态,如:在EIC办公室、分配给AE、AE邀请审稿人、AE指定审稿人、正在审稿、等待AE决定、等待EIC决定。为了确保公正的评审过程,我们要求在稿件中没有任何作者的身份(不包括作者的姓名、传记、隶属关系、求职信、签署的版权表格、识别脚注、致谢等)。如果你的手稿有很大一部分已经在会议上发表过,论文必须隐藏所有作者的身份,这样会议论文就可以被引用,就好像它是由不同的作者写的一样。请注意,通常你的技术成就是根据被引用的次数来评估的,而不是根据发表的论文数量。

loinleeai的博客 4433

iphone内存管理(一)

内存管理在iphone中一直是一个热点话题。通过一段时间的总结我准备与大家分享一下我对内存管理的一点认识和经验. 开始之前先给大家分享一些重要的信息 1。Iphone 3g有128M的内存。但是至少有一半已经用来运行OS了。这意味着你的程序可能只有区区40M的空间让你使用。但是请记住:你可能会在你程序只使用了3M时就收到一个内存警告. 2。iphone并不

gy188166520的博客 364

西工大总分396上岸学长的经验分享|西北工业大学通信考研信号与系统

以上就是我的一些经验,当然每个人的情况与学习习惯都是不一样,以上仅供大家参考,具体的学习进度安排等都要依据个人的实际情况而定。基础阶段:高数比较推荐武忠祥老师,他讲的内容难度比较合适,知识的梳理也比较完备,基础阶段主要集中做书上的例题,在基础阶段,我们很容易出现知识点遗忘现象,所以要及时回顾讲义知识点,这个时候做660的时候建议延迟两三章去练习(比如学完第三章,我在找时间把第一章的660习题做完,对答案)这里不建议硬生生的把讲义过一遍,可以配套做880基础篇,880这本资料还是极力推荐的。

xiaomage_mengma的博客 723

iphone内存管理(四)

(4).如果图大且同一张图使用次数不多就避免使用imageNamed UIImage有两种初始化方式 1.imageNamed 2.initWithContentsOfFile imageNamed这种方式虽然很方便。但是创建的是autorelease对象。而且有一个特殊的地方就是它创建的图像会拷贝一份作为缓存。下次请求同一个图片时将会先查看缓存。如

gy188166520的博客 301

【Agent】多智能体框架MetaGPT入门教程

创建一个 Action 类的子类 SimpleWriteCode,子类中定义好 prompt,并解析返回结果。在 MetaGPT 中,

酒酿小圆子呀~ 3140

一个基于ZYNQ、AXI接口的PL端卷积加速器,可由PS端调用(附Github源码)

一个基于ZYNQ,AXI接口的PL端卷积加速器,可由PS端调用开发板型号:Zynq-7000 SoC XC7Z305 FPGA开发平台:Vivado 2019.1;Github源码链接:https://github.com/CY0807/ZYNQ_PL_CONV_ACC。

跳跳骑士的博客 1306

IOS内存管理

1. 栈区(stack):由编译器自动分配释放,函数的参数值,局部变量等值。2. 堆区(heap):一般由开发人员分配释放,若不释放,则可能会引起内存泄漏。Objective-C提供了两种种内存管理方式:(MRC,手动引用计数器),(ARC,自动引用计数)。ARC作为苹果新提供的技术,苹果推荐开发者使用ARC技术来管理内存;

风·之痕的博客 8483

SSE(Server-Sent Events)完整使用示例

本篇使用Node.js 作为服务端,在浏览器客户端演示SSE的完整实例和演示。实现了一个基于 Server-Sent Events (SSE) 的实时数据推送功能。

oscar999的专栏 750

iOS内存管理

ARC是一种自动化的内存管理机制,它通过在编译时插入内存管理代码来自动管理对象的引用计数。在ARC机制下,系统会自动管理对象的引用计数,从而避免了因为忘记释放内存而导致的内存泄漏问题。弱引用是指一种不持有被引用对象的弱指针,它不会增加被引用对象的引用计数。当对象不再被引用时,其引用计数会减少1。开发者不需要手动管理对象的引用计数,从而避免了因为忘记释放内存而导致的内存泄漏和野指针等问题。使用ARC机制可以让开发者不需要手动管理对象的引用计数,从而避免了因为忘记释放内存而导致的内存泄漏和野指针等问题。

Alamo Fire 2805

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

【iOS开发】—— iOS内存管理

iOS内存管理

weixin_50990189的博客 3573

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

『iOS开发』 —— iOS内存管理

iOS内存管理 引用计数(Reference Count) iOS的内存管理基于引用计数这一机制,简单地说就是一个对象被其他对象持有时,引用计数+1,当不再被持有时-1,当引用计数减为零的时候对象不被任何人持有,就会被释放。 #### 内存管理的思考方式 * 自己生成的对象自己持有   `id obj = [[NSObject alloc] init];` * 不是自己生成的对象自己也能持有...

Peter_Huang0623的博客 800

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

iOS开发 - 内存管理

01、简介 内存是与CPU沟通的桥梁,计算机程序运行在内存,因此对内存的使用进行优化极为重要 02、内存管理说明 2.1 主要分类 内存管理主要分为自动内存管理和手动内存管理两大类 2.2 自动内存管理 2.2.1 由系统自动管理内存的方式,叫做自动内存管理 2.2.2 一些编程语言将自动内存管理称为垃圾回收,如Java

轻描淡写话程序 670

iOS中内存管理方案

系统提供的有不同的内存管理方案,大致有如下三种: TaggedPointer(对于一些小对象,比如说NSNumber,NSString等采用此种方案) NONPOINTER_ISA(64位架构下iOS应用程序) 散列表(散列表为复杂的数据结构,包含了引用计数表和弱引用表) TaggedPointer 以下2段代码能发生什么事?有什么区别? - (void)setName:...

小菜媛的博客 2737

ios内存管理

基础 强弱指针 1.强引用 __strong NSObject *obj;//加__strong就为强引用 2.弱引用 __weak NSObject *obj;//加__weak就为弱引用 3.区别 强引用持有对象,而弱引用不持有对象 强引用例子 __strong NSObject *obj1=[[NSObject alloc] init]; __strong NSObject *obj2=...

天台一只小蜗牛 274

iOS的内存管理

前言 iOS的开发语言是Objective-C,也就是对C语言进行了面向对象的封装。所以理解iOS的内存管理,必然要先去了解一下C语言的内存管理,这样才会更透彻。 C语言的内存四区 栈区(stack):由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。后进先出(LIFO)。 堆区(heap): 一般由程序员分配释放,若程序员不释放,程序结束时可能由操作系统回...

pengf_wuxiaowu的博客 427

iOS高级理论:内存管理

在 iOS 应用开发中,内存管理是非常重要的一个方面,合理管理内存可以避免内存泄漏和内存过度消耗,提高应用的性能和稳定性。iOS 中的内存管理主要是通过引用计数(reference counting)和自动释放池(autorelease pool)来实现的。

长沙火山 1808

ios内存管理(整理篇)

iOS内存管理机制 前言 今天学习了IOS中的内存管理机制,其中一些片段是由其他文章搬过来的,我记得有篇文章是这样写到,站在巨人的肩膀上,我只是一个整理者加了一些自己的理解 为什么要学习内存管理 虽然 ARC 帮我们解决了引用计数的大部分问题,一些年轻的 iOS 开发者仍然会做不好内存管理工作。他们甚至不能理解常见的循环引用问题,而这些问题会导致内存泄漏,最终使得应用运行缓慢或者被系统终止进程。 ...

qq_43364806的博客 738

【iOS】内存管理

本文系统梳理了iOS内存管理的核心机制,重点分析了内存分布模型、小对象优化、自动释放池等关键技术。内存分布方面,系统将3GB分配给五大区(栈、堆等)和保留区,1GB给内核区。小对象优化通过TaggedPointer技术实现高效存储,直接在指针中编码值数据,避免堆内存分配,提升3-100倍性能。自动释放池采用AutoreleasePoolPage双向链表结构,每页存储505个对象,通过哨兵对象界定释放范围,结合RunLoop实现内存自动释放。文章还深入解读了retain/release的引用计数管理逻辑...

2301_80095702的博客 1183
上一篇: IOS 字符串的用法
下一篇: IOS 类和对象
NameUseNsstring
博客等级 码龄11年 1粉丝 24原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值