OC之内存管理(个人笔记)
2015-09-15 13:32
295 查看
/*
1)为什么要进行内存管理?
移动设备的内存有限
2)内存管理的范围
所有的继承了NSObject类的对象
3)内存管理的原理
i,对象的所有权
一个对象的所有者(拥有者)
ii,对象的引用计数器
1)一个变量,
2)每个对象都有 3)8个字节
4)用来存储对象的所有者的个数
iii.对象引用计数器的作用
用来标识一个对象是否要销毁
1)如果引用计数器
> 0
不能销毁
2)如果引用计数器
== 0
销毁 (例外,对象为nil时候,计数器为0
但是不销毁)
iiii.引用计数器的操作:
1)
给对象发送
reatin 消息 +1
2)
........ release -1
3)
查看计数器的值 retainCount
4) 对象销毁
1)如果对象被销毁,他的内存空间被系统回收
2)对象销毁之前,会有一个临终
“dealloc方法”(对象销毁的时候,系统自动的调用这个对象的
dealloc方法)
3)对象销毁
(retainCount == 0)
5) 内存管理的分类:
1)MRC
手动内存管理
2)ARC
自动内存管理
*/
1.为什么基本数据类型可以放在“栈”中存储?“对象类型”却要放在堆中存储?
基本数据类型:大小固定
对象数据类型:大小不固定
2.为什么内存管理只管理“对象类型”?
代码执行完毕后,“堆内存”不会自动销毁,而“栈”内存会自动弹栈(释放)。
引用计数器:
简单来说,可以理解为:引用计数器表示有多少人正在使用这个对象
当没有任何人使用这个对象时,
系统才会回收这个对象,
也就是说
当对象的引用计数器为0时,
对象占用的内存就会被系统回收
如果对象的计数器不为0,那么在整个程序运行过程,它占用的内存就不可能被回收(除非整个程序已经退出
)
任何一个对象,刚生下来的时候,引用计数器都为1。(对象一旦创建好,默认引用计数器就是1)
当使用alloc、new或者copy创建一个对象时,对象的引用计数器默认就是1
要想管理对象占用的内存,就得学会操作对象的引用计数器
引用计数器的常见操作
给对象发送一条retain消息,
可以使引用计数器值+1(retain方法返回对象本身)
给对象发送一条release消息,
可以使引用计数器值-1
给对象发送retainCount消息,
可以获得当前的引用计数器值(通过%ld输出查看)
需要注意的是:
release并不代表销毁\回收对象,
仅仅是计数器-1
注意:我们只能通过操作对象计数器,间接控制对象的释放与否。
关闭ARC
选中项目->
选中All
->
搜索 Automatic
Reference
Counting
修改为No
dealloc
当一个对象的引用计数器值为0时
这个对象即将被销毁,其占用的内存被系统回收
系统会自动给对象发送一条dealloc消息
(因此,
从dealloc方法有没有被调用,就可以判断出对象是否被销毁)
dealloc方法的重写
一般会重写dealloc方法,
在这里释放相关资源,dealloc就是对象的遗言
一旦重写了dealloc方法,
就必须调用[super
dealloc],并且放在最后面调用
使用注意
不能直接调用dealloc方法
一旦对象被回收了,
它占用的内存就不再可用,
坚持使用会导致程序崩溃(野指针错误)为了防止调用出错,可以将“野指针”指向nil(0)。
僵尸对象
已经被销毁的对象(不能再使用的对象)
野指针
指向僵尸对象(不可用内存)的指针
给野指针发消息会报EXC_BAD_ACCESS/EXC_BREAKPOINT错误(message
sent to deallocatedinstance 0x100100350)
空指针
没有指向存储空间的指针(里面存的是nil,也就是0)
给空指针发消息是没有任何反应的,不会提示出错!
为了避免野指针错误的常见办法
在对象被销毁之后,将指向对象的指针变为空指针(p=nil)
苹果官方规定的内存管理原则
谁创建谁release
: 如果你通过alloc、new或copy、mutableCopy来创建一个对象,那么你必须调用release或autorelease
谁retain谁release
:只要你调用了retain,就必须调用一次release
总结一下就是
有加就有减
曾经让对象的计数器+1,就必须在最后让对象计数器-1
在自己负责的区域内(某个方法范围内、某个对象内等。):有+,就得有-。
@property 参数
控制set方法的内存管理
retain
: release旧值,retain新值(用于OC对象),要配合nonatomic使用。
assign
: 直接赋值,不做任何内存管理(默认,用于非OC对象类型)
copy
:release旧值,copy新值(一般用于NSString
*)
控制需不需生成set方法
readwrite
:同时生成set方法和get方法(默认)
readonly
:只会生成get方法
多线程管理
atomic
:性能低(默认)
nonatomic
:性能高(为iOS系统开发软件建议使用,为mac开发软件可以使用atomic)
控制set方法和get方法的名称
setter
: 设置set方法的名称,一定有个冒号:
getter
: 设置get方法的名称
@property (nonatomic, retain, setter =
setUserName:, getter =
getUserName)
NSString
*name;
一般只有BOOL类型的属性的get方法才会使用getter修改一下方法名为isXxxx,其他很少用的。
@property (nonatomic, assign) BOOL rich;
@property (nonatomic, assign, getter =
isRich) BOOL rich;
@class
遇到的问题:
1.要在某个类的头文件中使用另外一个类型,必须通过#import来引入另外一个类型的头文件,这样一旦被引用的头文件被修改,所有引用该头文件的文件都得修改重新编译,造成低效率
3.循环引用(循环依赖)问题
作用
可以简单地引用一个类
简单使用
@class
Dog;
仅仅是告诉编译器:
Dog是一个类;
并不会包含Dog这个类的所有内容
具体使用
在.h文件中使用@class引用一个类
在.m文件中使用#import包含这个类的.h文件
注意:继承某个类的时候不能使用@class,必须#import
@class 和 #import
作用上的区别
#import会包含引用类的所有信息(内容),
包括引用类的变量和方法
@class仅仅是告诉编译器有这么一个类,
具体这个类里有什么信息,
完全不知
效率上的区别
如果有上百个头文件都#import了同一个文件,或者这些文件又依次被#import,那么一旦最开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一遍
,编译效率非常低
相对来讲,使用@class方式就不会出现这种问题了
1)为什么要进行内存管理?
移动设备的内存有限
2)内存管理的范围
所有的继承了NSObject类的对象
3)内存管理的原理
i,对象的所有权
一个对象的所有者(拥有者)
ii,对象的引用计数器
1)一个变量,
2)每个对象都有 3)8个字节
4)用来存储对象的所有者的个数
iii.对象引用计数器的作用
用来标识一个对象是否要销毁
1)如果引用计数器
> 0
不能销毁
2)如果引用计数器
== 0
销毁 (例外,对象为nil时候,计数器为0
但是不销毁)
iiii.引用计数器的操作:
1)
给对象发送
reatin 消息 +1
2)
........ release -1
3)
查看计数器的值 retainCount
4) 对象销毁
1)如果对象被销毁,他的内存空间被系统回收
2)对象销毁之前,会有一个临终
“dealloc方法”(对象销毁的时候,系统自动的调用这个对象的
dealloc方法)
3)对象销毁
(retainCount == 0)
5) 内存管理的分类:
1)MRC
手动内存管理
2)ARC
自动内存管理
*/
1.为什么基本数据类型可以放在“栈”中存储?“对象类型”却要放在堆中存储?
基本数据类型:大小固定
对象数据类型:大小不固定
2.为什么内存管理只管理“对象类型”?
代码执行完毕后,“堆内存”不会自动销毁,而“栈”内存会自动弹栈(释放)。
引用计数器:
简单来说,可以理解为:引用计数器表示有多少人正在使用这个对象
当没有任何人使用这个对象时,
系统才会回收这个对象,
也就是说
当对象的引用计数器为0时,
对象占用的内存就会被系统回收
如果对象的计数器不为0,那么在整个程序运行过程,它占用的内存就不可能被回收(除非整个程序已经退出
)
任何一个对象,刚生下来的时候,引用计数器都为1。(对象一旦创建好,默认引用计数器就是1)
当使用alloc、new或者copy创建一个对象时,对象的引用计数器默认就是1
要想管理对象占用的内存,就得学会操作对象的引用计数器
引用计数器的常见操作
给对象发送一条retain消息,
可以使引用计数器值+1(retain方法返回对象本身)
给对象发送一条release消息,
可以使引用计数器值-1
给对象发送retainCount消息,
可以获得当前的引用计数器值(通过%ld输出查看)
需要注意的是:
release并不代表销毁\回收对象,
仅仅是计数器-1
注意:我们只能通过操作对象计数器,间接控制对象的释放与否。
关闭ARC
选中项目->
选中All
->
搜索 Automatic
Reference
Counting
修改为No
dealloc
当一个对象的引用计数器值为0时
这个对象即将被销毁,其占用的内存被系统回收
系统会自动给对象发送一条dealloc消息
(因此,
从dealloc方法有没有被调用,就可以判断出对象是否被销毁)
dealloc方法的重写
一般会重写dealloc方法,
在这里释放相关资源,dealloc就是对象的遗言
一旦重写了dealloc方法,
就必须调用[super
dealloc],并且放在最后面调用
使用注意
不能直接调用dealloc方法
一旦对象被回收了,
它占用的内存就不再可用,
坚持使用会导致程序崩溃(野指针错误)为了防止调用出错,可以将“野指针”指向nil(0)。
僵尸对象
已经被销毁的对象(不能再使用的对象)
野指针
指向僵尸对象(不可用内存)的指针
给野指针发消息会报EXC_BAD_ACCESS/EXC_BREAKPOINT错误(message
sent to deallocatedinstance 0x100100350)
空指针
没有指向存储空间的指针(里面存的是nil,也就是0)
给空指针发消息是没有任何反应的,不会提示出错!
为了避免野指针错误的常见办法
在对象被销毁之后,将指向对象的指针变为空指针(p=nil)
苹果官方规定的内存管理原则
谁创建谁release
: 如果你通过alloc、new或copy、mutableCopy来创建一个对象,那么你必须调用release或autorelease
谁retain谁release
:只要你调用了retain,就必须调用一次release
总结一下就是
有加就有减
曾经让对象的计数器+1,就必须在最后让对象计数器-1
在自己负责的区域内(某个方法范围内、某个对象内等。):有+,就得有-。
@property 参数
控制set方法的内存管理
retain
: release旧值,retain新值(用于OC对象),要配合nonatomic使用。
assign
: 直接赋值,不做任何内存管理(默认,用于非OC对象类型)
copy
:release旧值,copy新值(一般用于NSString
*)
控制需不需生成set方法
readwrite
:同时生成set方法和get方法(默认)
readonly
:只会生成get方法
多线程管理
atomic
:性能低(默认)
nonatomic
:性能高(为iOS系统开发软件建议使用,为mac开发软件可以使用atomic)
控制set方法和get方法的名称
setter
: 设置set方法的名称,一定有个冒号:
getter
: 设置get方法的名称
@property (nonatomic, retain, setter =
setUserName:, getter =
getUserName)
NSString
*name;
一般只有BOOL类型的属性的get方法才会使用getter修改一下方法名为isXxxx,其他很少用的。
@property (nonatomic, assign) BOOL rich;
@property (nonatomic, assign, getter =
isRich) BOOL rich;
@class
遇到的问题:
1.要在某个类的头文件中使用另外一个类型,必须通过#import来引入另外一个类型的头文件,这样一旦被引用的头文件被修改,所有引用该头文件的文件都得修改重新编译,造成低效率
3.循环引用(循环依赖)问题
作用
可以简单地引用一个类
简单使用
@class
Dog;
仅仅是告诉编译器:
Dog是一个类;
并不会包含Dog这个类的所有内容
具体使用
在.h文件中使用@class引用一个类
在.m文件中使用#import包含这个类的.h文件
注意:继承某个类的时候不能使用@class,必须#import
@class 和 #import
作用上的区别
#import会包含引用类的所有信息(内容),
包括引用类的变量和方法
@class仅仅是告诉编译器有这么一个类,
具体这个类里有什么信息,
完全不知
效率上的区别
如果有上百个头文件都#import了同一个文件,或者这些文件又依次被#import,那么一旦最开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一遍
,编译效率非常低
相对来讲,使用@class方式就不会出现这种问题了
相关文章推荐
- 兔子--查看Android Studio的版本信息
- 解决xcode的arc和第三方
- 第五届ccf认证考试第三题
- wifidog编译到openwrt
- Ubuntu安装JDK及环境变量配置步骤详解
- CSS 相对/绝对(relative/absolute)定位系列(四)
- 【转载】MFC 程序入口和执行流程
- noip2006 数列 (二进制)
- 快速排序
- hdoj 1237 简单计算器
- 二叉排序树删除节点
- 如何kill掉TaobaoProtect.exe
- 苹果操作系统(OS X和iOS)表情字符
- MongoDB学习日记(九):index
- 二维数组中的查找
- c++builder6.0 mdi窗体+自定义子窗体
- 对Hash Join的一次优化之--10104 trace-bucket
- 父子进程信号交互
- 用二叉堆实现优先队列
- Linux wait()函数 http://blog.163.com/lqy_super/blog/static/1997510212012112953858902/