内存管理(Memory Management,retain, dealloc,new,copy,MRC)
内存管理(Memory Management)
内存管理的方式
垃圾回收机制(gc, garbage collection), 油系统管理内存, 开发人员不需要关心内存, 系统会自动检测, 自动释放, 比如java
注: OC在1.0不支持垃圾回收机制, 到2.0时支持来及回收机制, 但是在iOS平台上苹果把OC的垃圾回收机制屏蔽掉了
iOS不支持垃圾回收机制, 如何管理内存?
通过引用计数(retain count)管理内存
通过引入计数来管理内存, 有两种方式
1.MRC, Manual Reference Count, 手动引用计数, 由开发人员通过引入计数来管理内存
MRC设置
2.ARC, Automatic Reference Count, 自动引入计数, 由系统通过引入计数来管理内存
图中行为 OC操作 OC方法
开灯 开辟内存空间, 生成对象 alloc/new/深copy
需要照明 持有对象 retain/浅copy
不需要照明释放对象 release/autorelease
关灯 回收内存空间, 丢弃对象 dealloc
注: 需要照明的人数, 就是引入计数
持有: 只要对这个对象做了引用计数+1的操作, 就叫人持有了这个对象
alloc, 从堆区开辟内存空间
引用计数: 从0变成1
自己创建的对象, 自己持有
Light *light = [[Light alloc] init]; NSLog(@"%lu", light.retainCount);
retain, 引用计数+1
持有某个对象
[light retain]; NSLog(@"%lu", light.retainCount);
安全使用对象: 先持有, 再使用
release, 引用计数-1
不再使用某个对象时, 释放该对象
[light release]; NSLog(@"%lu", light.retainCount); [light release];//light.retainCount = 0 // NSLog(@"%lu", light.retainCount);
僵尸对象
当对象的引入计数为0时, 就不能再使用这个对象了, 如果再使用这个对象, 对象就会变成僵尸对象
dealloc, 回收内存, 不允许手动调用, 当引用计数变成0时自动调用dealloc方法
Light.m #import "Light.h" @implementation Light - (void)dealloc { NSLog(@"关灯(回收内存)"); [super dealloc]; } @end
new, 相当于alloc + init
Light *light1 = [[Light alloc] init]; Light *light2 = [Light new]; NSLog(@"%lu, %lu", light1.retainCount, light2.retainCount); [light1 release]; [light2 release];
autorelease, 自动释放, 在未来的某段时间, 引用计数-1
Light *light3 = [[Light alloc] init]; [light3 autorelease]; NSLog(@"%lu", light3.retainCount);
注: 对一个对象使用autorelease操作, 这个对象不回立刻引用计数-1, 而是先放到自动释放池中, 当自动释放池结束, 会对池中的对象依次做引用计数-1
autoreleasepool只对调用了autorelease的对象起作用
copy
前提: 必须遵守<NSCopying>协议
Light *lightA = [[Light alloc] init]; Light *lightB = [lightA copy]; NSLog(@"%@", lightA); NSLog(@"%@", lightB); [lightA release]; [lightB release];
浅拷贝: 拷贝指针, 内存地址空间一样
lightB = [lightA retain];
深拷贝: 拷贝内存空间, 内存地址空间不一样
Light.m
- (id)copyWithZone:(NSZone *)zone { //zone: 内存空间 //1.深拷贝 Light *light = [[Light allocWithZone:zone] init]; return light; //2.浅拷贝 // return [self retain]; }
内存管理的原则
1.引用计数+1的操作(alloc, new, copy, retain)的次数 = 引用计数-1的操作(release, autoreleasse)的次数
2.对象的引用计数变为0, 就不能使用该对象
3.谁创建, 谁释放; 想使用, 先持有
4.当不使用某个对象时, 要及时释放
只有堆区的内存需要管理, 其他由系统管理
NSString *string = @"辉哥真帅!"; NSLog(@"%lu", string.retainCount); [string release]; NSLog(@"%lu", string.retainCount); [string retain]; NSLog(@"%lu", string.retainCount); NSString *str = [[NSString alloc]initWithFormat:@"辉哥帅的无法形容O(∩_∩)O哈哈哈~"]; NSLog(@"%lu", str.retainCount); [str release];
NSString,创建字符串, 判断常量区内有没有, 如果有就返回常量区的字符串; 如果没有, 就从堆区开辟一块内存区域存放字符串
NSString *str1 = [[NSString alloc] initWithFormat:@"1234567"]; NSLog(@"%lu", str1.retainCount); [str1 release];
Person.h #import <Foundation/Foundation.h> //姓名 性别 年龄 //自定义初始化方法 //便利构造器 //重写description方法 @interface Person : NSObject //属性的修饰词的默认值 //atomic, assign, readwrite @property (nonatomic, retain) NSString *name; @property (nonatomic, copy) NSString *gender; @property (nonatomic, assign) NSInteger age; - (instancetype)initWithName:(NSString *)name gender:(NSString *)gender age:(NSInteger)age; + (instancetype)personWithName:(NSString *)name gender:(NSString *)gender age:(NSInteger)age; @end
Person.m #import "Person.h" @implementation Person @synthesize age = _age, name = _name, gender = _gender; //修饰词是assign的setter和getter的实现 - (void) setAge:(NSInteger)age { _age = age; } - (NSInteger)age { return _age; } - (void)dealloc { [_name release]; [super dealloc]; } //修饰词是retain的setter和getter的实现 - (void)setName:(NSString *)name { if (_name != name) {//判断新对象的地址和原对象的地址是否一致, 如果一致, 就不需要改变; 如果不一致, 才需要改变 [_name release];//释放原来对象, 拥有新对象 _name = [name retain];//先持有, 才能安全使用 } } - (NSString *)name { return _name; } //修饰词是copy的setter和getter的实现 - (void)setGender:(NSString *)gender { if (_gender != gender) { [_gender release]; _gender = [gender copy]; } } - (NSString *)gender { return _gender; } - (instancetype)initWithName:(NSString *)name gender:(NSString *)gender age:(NSInteger)age { if (self = [super init]) { _name = name; _gender = gender; _age = age; } return self; } + (instancetype)personWithName:(NSString *)name gender:(NSString *)gender age:(NSInteger)age { return [[Person alloc] initWithName:name gender:gender age:age]; } - (NSString *)description { return [NSString stringWithFormat:@"name:%@ gender:%@ age:%ld", _name, _gender, _age]; } @end
NSString *nameString = [[NSString alloc] initWithFormat:@"adasfdhgvjhk"]; Person *person = [[Person alloc] init]; person.age = 18; person.name = nameString; [nameString release]; NSString *nameString1 = [[NSString alloc] initWithFormat:@"dfdfdfdf"]; person.name = nameString1; [nameString1 release]; [person release];
创建池子的两种写法
写法1
@autoreleasepool { Light *light4 = [[Light alloc] init]; [light4 autorelease]; }
写法2
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; Light *light5 = [[Light alloc] init]; [light5 autorelease]; [pool release];