黑马程序员——OC笔记之内存管理
2015-08-13 13:44
519 查看
------- android培训、java培训、iOS培训、.Net培训、期待与您交流!
----------
Objective-C提供了三种内存管理方式:
MannulReference Counting(MRC,手动管理, iOS4.1之前的版本)
automatic reference counting(ARC,自动引用计数,iOS4.1 之后推出的)
garbage collection(垃圾回收)。iOS不支持垃圾回收;
ARC作为苹果新提供的技术,苹果推荐开发者使用ARC技术来管理内存;
开发中如何使用:需要理解MRC,但实际使用时尽量用ARC
对其他非对象类型(基本数据类型)无效(int、char、float、double、struct、enum等)
只有OC对象才需要进行内存管理的本质原因:
因为OC对象存放于堆里面,非OC对象一般放在栈里面(栈内存会被系统自动回收)
Person *p = [Person alloc]init];
[p retain];
给对象发送一条release消息, 可以使引用计数器值-1
[p release];
给对象发送retainCount消息, 可以获得当前的引用计数器值(通过%ld输出查看)
NSLog(@"p->retainCount = %ld",p.retainCount);
注意: release并不代表销毁\回收对象, 仅仅是计数器-1
我们只能通过操作对象计数器,间接控制对象的释放与否。
以上这些操作必须在关闭ARC的情况下才能使用,Xcode默认是开启ARC。
2.设置ARC为NO
2)对self(当前)所拥有的的其他对象做一次release操作
注意
1)永远不要直接通过对象调用dealloc方法(实际上调用并不会出错)
2)一旦对象被回收了,它占用的内存就不再可用,坚持使用会导致程序崩溃(野指针错误)。为了防止调用出错,可以将“野指针”指向nil(0)。
Person.h
只要对象还有人在使用,那么这个对象就不会被回收;只要你想使用这个对象,那么就应该让这个对象的引用计数器+1;当你不想使用这个对象时,应该让对象的引用计数器-1;
2)“谁污染,谁治理。谁开发,谁保护”,跟这句口号一样,内存是,谁创建,谁release。谁retain,谁release。
(1)如果你通过alloc,new,copy来创建了一个对象,那么你就必须调用release或者autorelease方法
(2)只要你调用了retain,无论这个对象时如何生成的,你都要调用release
僵尸对象:所占内存已经被回收的对象,僵尸对象不能再被使用。(默认情况下xcode为了提高编码效率,没有开启僵尸对象检测)
Person *p = [Person alloc]init];// 1
[p release]; // 0
//此时p为野指针,也称之为僵尸对象
[p run];//野指针访问
[p retain];//僵尸对象死而不能复生
为避免不小心调用僵尸对象,可以将对象赋值nil
小刘开车去拉萨
main.m
Car.h
Car.m
Person.h
Person.m
----------
为什么要内存管理?
移动设备的内存及其有限,每个app所能占用的内存是有限制的。当app所占用的内存较多时,系统会发出内存警告,这时得回收一些不需要使用的内存空间。否则程序会卡死,甚至崩溃。因此必须学会内存管理。Objective-C提供了三种内存管理方式:
MannulReference Counting(MRC,手动管理, iOS4.1之前的版本)
automatic reference counting(ARC,自动引用计数,iOS4.1 之后推出的)
garbage collection(垃圾回收)。iOS不支持垃圾回收;
ARC作为苹果新提供的技术,苹果推荐开发者使用ARC技术来管理内存;
开发中如何使用:需要理解MRC,但实际使用时尽量用ARC
内存管理的范围:
任何继承了NSObject的对象(所有的OC对象,对象类型)对其他非对象类型(基本数据类型)无效(int、char、float、double、struct、enum等)
只有OC对象才需要进行内存管理的本质原因:
因为OC对象存放于堆里面,非OC对象一般放在栈里面(栈内存会被系统自动回收)
内存管理的原理:
在每个对象内部,都有一个4个字节的引用计数器,表示“对象的引用个数”,当用new,alloc,copy创建一个新对象后,计数器的值为1。当对象调用retain方法时,计数器加1,当调用release方法是,计数器减1。当计数器的值减为0后,对象会被回收。在对象被销毁之前,系统会向对象发送一条dealloc消息,此时系统就会帮我们释放该对象所占用的内存。1、引用计数器的常见操作
给对象发送一条retain消息, 可以使引用计数器值+1(retain方法返回对象本身)Person *p = [Person alloc]init];
[p retain];
给对象发送一条release消息, 可以使引用计数器值-1
[p release];
给对象发送retainCount消息, 可以获得当前的引用计数器值(通过%ld输出查看)
NSLog(@"p->retainCount = %ld",p.retainCount);
注意: release并不代表销毁\回收对象, 仅仅是计数器-1
我们只能通过操作对象计数器,间接控制对象的释放与否。
以上这些操作必须在关闭ARC的情况下才能使用,Xcode默认是开启ARC。
2、关闭ARC:
1.设置项目信息2.设置ARC为NO
3、判断对象是否被回收
1)一定要[super dealloc],而且要放到最后,意义是:先释放子类占用的空间再释放父类占用的空间2)对self(当前)所拥有的的其他对象做一次release操作
-(void)dealloc { [_car release]; [super dealloc]; }
注意
1)永远不要直接通过对象调用dealloc方法(实际上调用并不会出错)
2)一旦对象被回收了,它占用的内存就不再可用,坚持使用会导致程序崩溃(野指针错误)。为了防止调用出错,可以将“野指针”指向nil(0)。
Person.h
#import <Foundation/Foundation.h> @interface Person : NSObject @property int age; @endPerson.m
#import "Person.h" @implementation Person //监测对象是否被回收的方法 -(void)dealloc{ //释放子类对象 NSLog(@"对象被销毁了~"); //释放父类 [super dealloc]; } @endmain.m
#import <Foundation/Foundation.h> #import "Person.h" int main(int argc, const char * argv[]) { @autoreleasepool { //用Person 类实例化一个实例对象 Person *p = [Person new]; // 对象有没有所有者? 有 //证明有一个所有者 NSUInteger count = p.retainCount; NSLog(@"count = %lu",count); // 1 //使用引用计数器+1 [p retain]; NSLog(@"p.retainCount = %lu",p.retainCount); //2 //如果要回收对象? 应该想办法 retatinCount = 0 [p release]; NSLog(@"p.retainCount = %lu",p.retainCount); //1 [p release]; //此处执行后,p的空间被回收 //0 //证明p的空间被释放了,可以在在Person类中,重写dealloc方法 } return 0; }
内存管理的原则
1)原则只要对象还有人在使用,那么这个对象就不会被回收;只要你想使用这个对象,那么就应该让这个对象的引用计数器+1;当你不想使用这个对象时,应该让对象的引用计数器-1;
2)“谁污染,谁治理。谁开发,谁保护”,跟这句口号一样,内存是,谁创建,谁release。谁retain,谁release。
(1)如果你通过alloc,new,copy来创建了一个对象,那么你就必须调用release或者autorelease方法
(2)只要你调用了retain,无论这个对象时如何生成的,你都要调用release
单个对象的内存管理(野指针)
野指针访问:访问了一块坏的内存(已经被回收的,不可用的内存)。僵尸对象:所占内存已经被回收的对象,僵尸对象不能再被使用。(默认情况下xcode为了提高编码效率,没有开启僵尸对象检测)
Person *p = [Person alloc]init];// 1
[p release]; // 0
//此时p为野指针,也称之为僵尸对象
[p run];//野指针访问
[p retain];//僵尸对象死而不能复生
打开僵尸对象检测
为避免不小心调用僵尸对象,可以将对象赋值nil
Person *p = [Person alloc]init];// 1 [p release]; // 0 p = nil; [p run];//相当于[nil retain],空指针调用方法无反应 [p retain];//相当于[nil retain],不会报错,但应避免
多个对象内存管理(野指针)
举个栗子�小刘开车去拉萨
main.m
#import <Foundation/Foundation.h> #import "Person.h" int main(int argc, const char * argv[]) { @autoreleasepool { Person *p = [[Person alloc]init];// 1 Car *bmw=[Car new];// 1 bmw.speed=80; // [p setCar:bmw];//可以用点语法替换 p.car=bmw; NSLog(@"bmw retainCount=%lu",[bmw retainCount]); [p goLasa]; [p goLasa]; [bmw release];//_car--->1 NSLog(@"bmw retainCount=%lu",[bmw retainCount]); // [bmw release];//将此句放在人的dealloc方法里,可以让车先于人亡,同时不影响人的方法的调用,否则会出现人没车还能开车的不合理现象 [p goLasa]; [p release]; } return 0;
Car.h
#import <Foundation/Foundation.h> @interface Car : NSObject { int _speed; } -(void)setSpeed:(int)speed; -(void)run; @end
Car.m
@implementation Car - (void)dealloc { NSLog(@"车已经毁了"); [super dealloc]; } -(void)setSpeed:(int)speed{ _speed=speed; } -(void)run{ NSLog(@"小明正开车在以%d码的速度去拉萨",_speed); } @end
Person.h
#import <Foundation/Foundation.h> #import "Car.h" @interface Person : NSObject { Car *_car; } -(void)setCar:(Car*)car; -(void)goLasa; @end
Person.m
#import "Person.h" @implementation Person - (void)dealloc { [_car release];//在人挂掉之前让车报废 _car--->0 NSLog(@"人已经挂了"); [super dealloc]; } -(void)setCar:(Car*)car{ _car=[car retain];//_car--->2 } -(void)goLasa{ [_car run]; } @end
相关文章推荐
- Lua的内存管理浅析
- 深入探讨PHP中的内存管理问题
- linux 内存管理机制详细解析
- 解析PHP中的内存管理,PHP动态分配和释放内存
- javascript内存管理详细解析
- JavaScript内存管理介绍
- Cocos2d-x的内存管理总结
- 模拟实现C语言中的内存管理
- javascript错误的认识不用关心内存管理
- Python深入学习之内存管理
- 简单说说STL的内存管理
- InnoDB存储引擎的内存管理机制
- jemalloc优化MySQL、Nginx内存管理
- #无私分享《传智播客2011版。net平台c#视频》全套哦30.7G
- 【转】JVM内存管理:深入垃圾收集器与内存分配策略
- JavaScript内存管理介绍
- 25条提高iOS App性能的建议和技巧
- ios高效开发二--ARC跟block那点事
- C/C++内存管理详解
- Oracle 自动管理 ASMM