内存管理(上)
来源:互联网 发布:初中生自学编程难吗 编辑:程序博客网 时间:2024/06/01 12:08
一、内存管理的方式
造成程序崩溃的主要原因:
1. 野指针:指针所指向的空间已经被回收,但是依然使用该指针访问已经被收回的空间(野指针不会立刻造成程序崩溃)。
2. 内存溢出:所需内存超过了给定内存的上限。
3. 内存泄漏:内存已经被开辟,但是没有被释放。
iOS支持两种内存管理方式:ARC和MRC。
MRC的内存管理机制是:引用计数。ARC是基于MRC的。
ARC与MRC的区别:
MRC:手动引用计数,对象的创建以及对象的所有权的释放都需要我们自己去写代码操作,对我们自己的要求较高。
ARC:iOS5.0之后出现的,是编译器特性,系统会在合适的位置自动的帮我们添加上release/autorelease代码,我们不需要自己去写代码释放所有权,ARC不是垃圾回收,本质还是MRC。
二、引用计数机制,影响引用计数的各种方法
OC采用引用计数机制管理内存,每个对象都有一个引用计数器,用来记录当前对象的引用次数。当一个新的引用指向对象时,引用计数器就加1,当去掉一个引用时,引用计数就减1。当引用计数到零时,该对象的空间就被系统回收。
影响引用计数的方法:
//alloc 使应用计数 0---1.//retain 使引用计数在原有的基础上+1Person *p2 = [p1 retain];NSLog(@"%lu", [p2 retainCount]);Person *p3 = [p2 retain];NSLog(@"%lu", [p3 retainCount]);//注意:引用计数指的是开辟的空间的引用计数,不是指针变量的引用计数,指针变量是没有引用计数的.//release 在引用计数原有的基础上-1(立刻减1).//autorelease 延迟释放,必须和自动释放池结合使用.也是使对象的引用计数-1,但是会在出了离其最近的自动释放池后将引用计数-1[p3 release];NSLog(@"%lu", [p2 retainCount]);[p2 autorelease];NSLog(@"%lu", [p1 retainCount]);[p1 release];//dealloc 回收对象的空间,当对象的引用计数变为0时,该方法会自动调用.如果想查看对象的空间是否被回收,可以重写该方法,但是注意需要调用super.注意:永远不要手动的调用dealloc//copy:新创建一个对象,引用计数由0变成1,原对象的引用计数不发生变换.
对象的引用计数只有在堆区才是有意义的。
三、内存管理的基本原则
只要使用了alloc,retain或者copy让内存的引用计数增加了,就需要使用release或者autorelease让内存的引用计数减少。在一段代码内,增加和减少的次数要相等。
如果增加的次数大于减少的次数,会造成内存泄漏。
如果增加的次数小于减少的次数,会造成过度释放。
如果增加的次数等于减少的次数,还继续访问,造成野指针问题。
四、协议
协议:本质上就是一堆方法的声明,哪个类遵循该协议,该类就需要实现协议中的方法。一个类可以遵循多个协议,每个协议用逗号隔开。
协议中的方法分两种:必须实现的,用@required关键字修饰。默认的,选择实现的,用@optional关键字修饰。
实现一个基础版的协议流程:
1. 创建一个协议(.h文件)。
2. 声明协议中的方法。
3. 让某个类遵循协议(导入协议文件,在该类父类名的后面写<协议名>)。
4. 该类遵循协议后需要实现协议中的方法。
5. 创建该类对象,执行协议方法。
示例:
协议文件:
@protocol MyProtocol <NSObject>@required- (void)sayHello;@optional- (void)sayBye;@end
.h文件:
#import "MyProtocol.h"@interface Person : NSObject<MyProtocol>@property (nonatomic, copy) NSString *name;@end
.m文件实现协议方法:
- (void)sayHello{ NSLog(@"你好,妹子,我是%@,请问,这是你掉的板砖吗?", self.name);}- (void)sayBye{ NSLog(@"再见,妹纸~~~~下次再XXXX");}
五、内存拷贝
拷贝:如果自定的类想要实现copy,必须遵循NSCopying协议,并实现协议中的方法,才可以实现copy,不然会crash。
根据NSCoping中copyWithZone:方法的实现不同,拷贝分为三种类型:
1. 伪拷贝:拷贝地址,相当于retain操作,引用计数加1。
- (id)copyWithZone:(NSZone *)zone{ return [self retain];}
2. 浅拷贝:对象开辟新的空间,但是两个对象的实例变量指向同一块空间。
- (id)copyWithZone:(NSZone *)zone{ Person *p = [[Person allocWithZone:zone] init]; return p;}
3. 深拷贝:对象开辟新的空间,两个对象的实例变量也指向不同的空间。
- (id)copyWithZone:(NSZone *)zone{ Person *p = [[Person allocWithZone:zone] init]; p.name = [self.name mutableCopy]; return p;}
- Linux内存管理(上)
- Linux内存管理(上)
- Linux内存管理(上)
- Linux内存管理(上)
- Linux内存管理(上)
- Linux内存管理(上)
- Linux内存管理(上)
- Linux内存管理(上)
- Linux内存管理(上)
- Linux内存管理(上)
- Linux内存管理(上)
- Linux内存管理(上)
- Linux内存管理(上)
- Linux内存管理(上) .
- Linux内存管理(上)
- C++内存管理(上)
- iOS内存管理上
- Linux内存管理(上)
- 修改鼠标悬停样式
- 使用javac命令编译Servlet类
- Android 增量更新完全解析 是增量不是热修复
- SpringBoot搭建简单留言板项目
- java23种设计模式
- 内存管理(上)
- jQuery-easyUI-combobox默认值问题
- 区间覆盖问题
- [Python] 单次迭代带来的问题
- HOLUX M1200-E 蓝牙GPS轨迹记录器的历史轨迹数据读取
- SpringBoot学习笔记(2) Spring Boot的一些配置
- c++ override 关键字
- 【机试题】迷宫寻路--拼多多2018校招内推编程题
- 对于备份恢复的理解