iOS学习17之OC内存管理
1、内存管理的方式
1> iOS应用程序出现Crash(闪退),90%的原因是因为内存问题。
2> 内存问题
- 野指针异常:访问没有所有权的内存,如果想要安全的访问,必须确保空间还在
- 内存泄露:空间使用完之后没有及时释放
- 过度释放:对同一块存储空间释放多次,立刻crash
- 内存溢出:所有存储空间被占用
3> 管理内存的三种方式
垃圾回收机制:程序员只需要开辟存储空间,系统会自动回收内存。java采用的该机制
MRC:手动引用计数机制,由开发人员开辟空间,手动添加影响引用计数增加或减少的方法,能够灵活的控制空间何时释放
ARC:自动引用计数机制,是iOS5.0推出的,基于MRC,不需要程序员手动添加管理内存的代码,编译器会在合适的地方自动添加管理内存的代码
MRC和ARC都是采用引用计数来管理对象内存
4> iOS的内存管理
iOS支持两种内存管理方式:ARC和MRC。
MRC的内存管理机制是:引用计数。
ARC是基于MRC的。
2、引用计数机制
1> 引用计数

OC采用引用计数机制管理内存,每个对象都有一个引用计数器,用来记录当前对象的引用次数。
iOS采用引用计数来管理内存,当你想拥有这个对象的时候,需要使该对象的引用计数+1,使用完这个对象的时候,使该对象的引用计数-1,当对象的引用计数为时,表示没有任何对象对该对象持有,那么这时候系统会自动调用dealloc方法来回收该对象的存储空间。
2> 影响引用计数的方法
retainCount 获取对象的引用计数。(retainCount它是MRC才有的机制,所以如果使用需要将ARC改为MRC)。
ARC改为MRC:点击过程名 ---> Build Setting ---> 将Objective - C Automatic Counting 由YES改为NO
① 使计数器加1的方法:alloc,retain,copy。
+alloc 开辟内存空间,让被开辟的内存空间的引用计数从变为.
-retain 引用计数加1,如果对象之前引用计数为,retain之后变为,如果引用计数是5,retain之后变为6。
-copy 把某一对象的内容拷贝一份,拷贝出新的对象,原有对象的引用计数不变,新的对象的引用计数变1。
② 使计数器减1的方法:release,autorelease。
-release 引用计数立即减1,如果对象之前的引用计数为4,release之后变为3,如果之前引用计数是1,release之后变为0,内存被系统回收。
-autorelease 未来的某一时刻引用计数减1,如果对象之前引用计数为4,autorelease之后仍然为4,未来某个时刻会变为3,这个某一时刻指的是碰到自动释放池之后才会释放。
3> autoreleasepool的使用
通过autoreleasepool自动释放池,控制autorelease对象的释放。向一个对象发送autorelease消息,该对象就会添加到离autorelease最近的自动释放池中,当自动释放池销毁时,为池中的每一个对象发送release消息。
定义一个自动释放池
第一种方式
// 第一种形式
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // pool 1
NSLog(@"pool = %lu", pool.retainCount); Person *p1 = [[Person alloc] init];
NSLog(@"p1 = %lu", p1.retainCount); [p1 retain]; // [p1 autorelease]; // 未来的某一时刻-1
NSLog(@"p1 = %lu", p1.retainCount); // [pool release]; // 销毁自动释放池
NSLog(@"p1 = %lu", p1.retainCount); //
第二种方式
// 在iOS5.0之后推荐使用
@autoreleasepool {
Person *p5 = [[Person alloc] init];
[p5 autorelease];
}
总结:自动释放池的作用:自动释放池会在销毁之前检查内部有没有autorelease对象,如果有autorelease对象,让该对象的引用计数做一次-1操作
4> dealloc
-dealloc 是继承自父类的方法,当对象引用计数为0的时候,由对象自动调用,销毁该对象的空间。
重写 dealloc 方法,验证对象的空间是否被回收。
- (void)dealloc {
NSLog(@"%@对象被销毁", self);
[super dealloc]; // 类对该方法的实现才是真正的回收空间
}
3、内存管理原则
凡是使用alloc,retain让对象的引用计数+1,相应的就该使用release或者autorelease让对象的引用计数-1,也就是说增加的次数要和减少的次数相等,才能保证对象的引用计数最终为0,对象才会被销毁。
1> 内存泄露:增加的次数大于减少的次数
Person *person2 = [[Person alloc] init]; //
[person2 retain]; //
[person2 release]; //
2> 过度释放:增加的次数小于减少的次数
Person *person1 = [[Person alloc] init];
[person1 retain];
[person1 release];
[person1 release];
[person1 release]; // 过度释放
3> 野指针异常:增加的次数等于减少的次数,还将继续访问
Person *person = [[Person alloc] init];
[person retain];
[person release];
[person release];
person = nil; // 对象置为nil, 防止野指针异常
NSLog(@"person = %lu", person.retainCount);
4、协议
1> 概述
2> 协议的定义
协议的定义:command + n —> 选择OS X下的 source —> Objective-C File —> Next —> 弹出下图。
3> 协议的方法
协议中的方法默认是必须实现的,即@required。关键字@optional修饰的方法是可选的,可实现也可不实现。
#import <Foundation/Foundation.h>
@protocol SayHello <NSObject>
// 协议中的方法有两种,一种必须实现的,另一种是可选择实现的。
//必须实现的方法,默认方法就是必须实现的。
@required
- (void)sayHello;
//可选择实现的方法。
@optional
- (void)sayByeBye;
@end
4> 协议的使用
在类的.h文件中,在当前类父类的后面使用一对尖括号<>,遵循协议一个类可以遵循多个协议,每个协议用逗号隔开。
5、拷贝
1> copy概述
跟retain不同,一个对象想要copy,生成自己的副本,需要服从NSCopying协议,定义copy的细节(如何copy)。如果类没有接受NSCopying协议而给对象发送copy消息,会引起crash。
2> NSCopying协议中的方法
选中NSCopying,按住Command + 鼠标左键,进入协议查看协议中方法
@protocol NSCopying - (id)copyWithZone:(nullable NSZone *)zone; @end
3> 根据copyWithZone:方法的实现不同,拷贝分为三种类型
- 伪拷贝 : 拷贝地址,相当于retain,引用计数+1
copyWithZone: 方法的实现
- (id)copyWithZone:(NSZone *)zone {
// 伪拷贝 : 拷贝地址,相当于retain,引用计数+1
return [self retain];
}
浅拷贝:对象开辟新的空间,但两个对象的实例变量指向同一块存储空间
copyWithZone: 方法的实现
- (id)copyWithZone:(NSZone *)zone {
// 浅拷贝:对象开辟新的空间,但两个对象的实例变量指向同一块存储空间
Person *person = [[Person allocWithZone:zone] init];
person.name = self.name;
person.gender = self.gender;
return person;
}
深拷贝:对象开辟新的存储空间,并且两个对象的实例变量指向不同的存储空间
copyWithZone: 方法的实现
- (id)copyWithZone:(NSZone *)zone {
// 深拷贝:对象开辟新的存储空间,并且两个对象的实例变量指向不同的存储空间
Person *person = [[Person allocWithZone:zone] init];
person.name = [self.name mutableCopy];
person.gender = [self.gender mutableCopy];
return person;
}
4> 浅拷贝与深拷贝的区别(面试题)
如果是深拷贝,那么成员对象的地址和之前的地址不同,如果是浅拷贝,成员变量的地址和之前的地址相同。
iOS学习17之OC内存管理的更多相关文章
- 【原】iOS学习18之OC内存管理高级
1.属性的内存管理 1> 属性的语义特性 2> assign下的属性内部实现 @property (nonatomic, assign) NSString *name; @synthesi ...
- iOS学习笔记之ARC内存管理
iOS学习笔记之ARC内存管理 写在前面 ARC(Automatic Reference Counting),自动引用计数,是iOS中采用的一种内存管理方式. 指针变量与对象所有权 指针变量暗含了对其 ...
- iOS学习之Object-C语言内存管理
一.内存管理的方式 1.iOS应用程序出现Crash(闪退),90%的原因是因为内存问题. 2.内存问题: 1)野指针异常:访问没有所有权的内存,如果想要安全的访问,必须 ...
- iOS学习之Object-C语言内存管理高级
一.属性的内存管理
- iOS学习之C语言内存管理
一.存储区划分 按照地址从高到低的顺序:栈区,堆区,静态区,常量区,代码区 1.栈区:局部变量的存储区域 局部变量基本都在函数.循环.分支中定义 栈区的内存空 ...
- iOS经典面试题总结--内存管理
iOS经典面试题总结--内存管理 内存管理 1.什么是ARC? ARC是automatic reference counting自动引用计数,在程序编译时自动加入retain/release.在对象被 ...
- OC 内存管理机制总结
OC 内存管理机制总结 一:OC内存管理机制目前分为两块,其一自动内存管理机制,其二手动内存管理机制: 1.首先我们从自动内存管理机制讲起: 1)什么是自动内存管理机制,自动内存管理机制就是程序中所创 ...
- OC内存管理-OC笔记
内存管理细节:http://blog.sina.com.cn/s/blog_814ecfa90102vus2.html 学习目标 1.[理解]内存管理 2.[掌握]第一个MRC程序 3.[掌握]内存管 ...
- OC内存管理总结,清晰明了!
<span style="font-size:18px;">OC内存管理 一.基本原理 (一)为什么要进行内存管理. 由于移动设备的内存极其有限.所以每一个APP所占的 ...
随机推荐
- 常用iOS的第三方框架
图像:1.图片浏览控件MWPhotoBrowser 实现了一个照片浏览器类似 iOS 自带的相册应用,可显示来自手机的图片或者是网络图片,可自动从网络下载图片并进行缓存.可对图片进行缩放等 ...
- NYOJ题目1045看美女
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAskAAAK5CAIAAADCdSR7AAAgAElEQVR4nO3dP3Lbuv434HcT7r2Q1F
- 瓦片地图与geoserver发布
本文主要包括以下内容 TileMill生成Tile影像金字塔(.mbtiles压缩文件) Mbutil(https://github.com/mapbox/mbutil)解压缩 Apache HTTP ...
- 关于java中的异常问题 1
1.首先参考一下关于java异常处理方面的知识 查看博客http://lavasoft.blog.51cto.com/62575/18920/ 这里介绍的很好,下面从中学习到一些东西,摘抄如下: 1. ...
- 20145206邹京儒《Java程序设计》实验报告一:Java开发环境的熟悉(Windows+IDEA)
20145206<Java程序设计>实验报告一:Java开发环境的熟悉(Windows+IDEA) 实验内容及步骤 1.使用JDK编译.运行简单的Java程序: 建立实验目录: 在IDEA ...
- How to increase TX Power Signal Strength of WiFi
转自:https://www.blackmoreops.com/2013/10/27/how-to-increase-tx-power-signal-strength-of-wifi/ This gu ...
- JAVA基础学习之final关键字、遍历集合、日期类对象的使用、Math类对象的使用、Runtime类对象的使用、时间对象Date(两个日期相减)(5)
1.final关键字和.net中的const关键字一样,是常量的修饰符,但是final还可以修饰类.方法.写法规范:常量所有字母都大写,多个单词中间用 "_"连接. 2.遍历集合A ...
- Delphi多线程开发注意事项
Q1: 多线程中需避免多个线程同时向全局变量进行写入操作,导致访问冲突问题. A1: 可以通过使用加锁机制(比如:临界区.互斥.信号量)解决此问题. Q2:多线程中对于结构体和CLASS类型的全局变 ...
- 【PHP自定义显示系统级别的致命错误和用户级别的错误】
使用方法set_error_handler可以自定义用户级别的错误和系统级别的错误信息显示和处理 用户级别的错误使用trigger_error方法产生一个用户级别的错误信息 代码示例: 系统级别的错误 ...
- JavaScript - 事件流
事件流 事件冒泡就是事件沿DOM树向上传播,在没一级节点上都会发生,直至传播到document对象. 事件捕获正好相反,但是老版本的浏览器不支持,因此很少有人使用事件捕获. 事件处理程序 HTMl 事 ...