C语言内存管理
char *p = malloc(100); //在堆中开辟100个字节空间
strcpy(p,"hello");
NSLog(@"p = %s",p);
fun1(p);
fun2(p);
//C内存管理的隐患:
//free(p); //1.当fun1,fun2没用完malloc空间,执行了free,造成提前释放--野指针
//2.担心传出去的空间,别人没用完,所有人都不去释放--内存泄漏
free(p); //3.所有人都担心内存没释放,都执行free,造成重复释放 -- 奔溃
//OC中改善内存管理的机制--引用计数
//引用计数: ARC 、MRC
//ARC: 自动引用计数-(默认)
//MRC: 手动引用计数## 标题 ##
ARC
int main(int argc, const char * argv[]) {
@autoreleasepool { //自动释放池
// insert code here...
//ARC执行过程:
//先执行@autoreleasepool括号内->dealloc->自动释放池括号外
Person *per = [[Person alloc] init];
NSLog(@"开辟空间");
}
NSLog(@"程序即将结束");
return 0;
}
//析构方法:释放内存的方法;程序执行完毕,进入dealloc,说明已经释放该对象
- (void)dealloc
{
NSLog(@"Person dealloc");
}
MRC
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
//MRC执行过程:
//release:只要对象的引用计数为0->立即dealloc(不会等到自动释放池结束)(推荐)
//autoRelease: 把引用计数-1抛给自动释放池,退出自动释放池立即执行dealloc
Person *per = [[Person alloc] init];
NSLog(@"开辟空间");
[per release]; //引用计数-1; 减到0时,才释放(调用dealloc)
//[per autorelease]; //有延迟的引用计数-1;
NSLog(@"空间-1");
}
NSLog(@"应用程序执行结束");
return 0;
}
MRC的Retain调用
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
Person *xiaoM = [[Person alloc] init];
Person *xiaoQ = [xiaoM retain]; //引用计数+1
Person *xiaoB = [xiaoQ retain];
NSLog(@"引用计数:%ld",[xiaoQ retainCount]); //获取引用计数
[xiaoM release]; //引用计数-1,计数还剩1
NSLog(@"-1后,引用计数:%ld",[xiaoM retainCount]); //获取引用计数
//[xiaoM release]; err 一定要使用内存管理黄金法则
[xiaoQ release];
[xiaoB release];
//释放的值,再打印无意义
//NSLog(@"retainCount = %ld",[xiaoB retainCount]);
//结论: 只要有alloc、retain、copy,就一定对应有release-内存管理黄金法则
}
return 0;
}
字符串的内存管理
NSString *str = [[NSString alloc] init];
//在字符串中不能用retainCount来获取引用计数
NSLog(@"retainCount = %ld",[str retainCount]); //-1
//1.NSString进行retain
NSString *str1 = [str retain]; //引用计数+1
//字符串通过打印地址的方式,验证引用计数是否+1
NSLog(@"str1:%p,str: %p",str1,str);
[str release]; //内部遵循内存管理的黄金法则
[str1 release];
NSMutableString *mutStr = [[NSMutableString alloc] init];
//2.NSMuatableString进行retain
NSMutableString *mutStr1 = [mutStr retain]; //引用计数+1
NSLog(@"mutStr:%p,mutStr1:%p",mutStr,mutStr1);
//结论:可变与不可变字符串进行retain,引用计数都+1;
//3.NSString进行copy
NSString *str2 = [str copy]; //引用计数+1
NSLog(@"str: %p,str2: %p",str,str2);
//4.NSMuatableString进行copy
NSString *str3 = [mutStr1 copy]; //引用计数不+1
NSLog(@"str3 = %p,mutstr1=%p",str3,mutStr1);
//结论:不可变进行copy引用计数+1,可变不+1;
//5.NSString进行mutableCopy
NSMutableString *mutStr2=[str3 mutableCopy]; //引用计数不+1
NSLog(@"mutStr2=%p,str3 = %p",mutStr2,str3);
//6.NSMutableString进行mutableCopy
NSMutableString *mutStr3 = [mutStr2 mutableCopy];//引用计数不+1
NSLog(@"mutstr3=%p,mutStr2=%p",mutStr3,mutStr2);
//结论:可变与不可变字符串进行mutableCopy,引用计数都不+1;
//
//深拷贝:引用计数不+1、字符串的mutableCopy始终为深拷贝
//浅拷贝:引用计数+1、字符串的retain始终为浅拷贝
数组的内存管理
Person *p1 = [[Person alloc] init];
Person *p2 = [[Person alloc] init];
Person *p3 = [[Person alloc] init];
//1. 当元素对象放入数组,每一个对象的引用计数都+1
NSMutableArray *mutArr = [[NSMutableArray alloc] initWithObjects:p1,p2,p3, nil];
NSLog(@"p1 count = %ld",p1.retainCount); //2
NSLog(@"p2 count = %ld",p2.retainCount); //2
NSLog(@"p3 count = %ld",p3.retainCount); //2
//2.在数组中添加一个对象,那么该对象的引用计数+1
[mutArr addObject:p1];
NSLog(@"p1 count = %ld",p1.retainCount); //3
NSLog(@"p2 count = %ld",p2.retainCount); //2
NSLog(@"p3 count = %ld",p3.retainCount); //2
//3.数组中移除一个对象,那么该对象的引用计数-1
[mutArr removeObject:p3];
NSLog(@"p1 count = %ld",p1.retainCount); //3
NSLog(@"p2 count = %ld",p2.retainCount); //2
NSLog(@"p3 count = %ld",p3.retainCount); //1
//4.数组中溢出所有对象,那么每一个对象的引用计数都-1
[mutArr removeAllObjects];
//[mutArr release];
NSLog(@"p1 count = %ld",p1.retainCount); //1
NSLog(@"p2 count = %ld",p2.retainCount); //1
NSLog(@"p3 count = %ld",p3.retainCount); //1
[p1 release]; //引用计数为0,调用dealloc
[p2 release]; //引用计数为0,调用dealloc
[p3 release]; //引用计数为0,调用dealloc
总结
//1.回顾C内存管理的缺陷
//a. 提前释放 b. 重复释放 c. 没有释放
//2.引用计数的概念:
//a. ARC: 自动引用计数,退出自动释放池,系统自动会释放内存空间
//b. MRC: 手动引用计数;
//b1. 内存管理的黄金法则;
//b2. MRC默认的调用方法及标准写法
//调用方法:retain、retainCount、release、dealloc
//标准写法:记住复合类内存管理,字符串在类中的内存管理
//3. 字符串的内存管理
//深拷贝与浅拷贝的概念
//4. 数组的内存管理
//记住4个结论
//5.release与autorelease
//release: 引用计数-1(MRC推荐使用)
//autorelease: 有延时的引用计数-1
test
main:
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
//创建对象
Engine *eng = [[Engine alloc] init];
Engine *eng2 = [[Engine alloc] init];
Car *car1 = [[Car alloc] initWithEngine:eng];
[car1 setEngine:eng2];
//释放对象
[eng2 release];
[eng release];
[car1 release];
}
return 0;
}
car:
@implementation Car
//setter函数
-(void)setEngine:(Engine *)engine
{
if (_engine != engine) {
[_engine release];
_engine = [engine retain];
}
}
//getter函数
-(Engine *)engine
{
return _engine;
}
//Car对象初始化
-(id)initWithEngine:(Engine *)engine
{
self = [super init];
if (self) {
// _engine = [engine retain];
_engine = engine;
[engine retain];
}
return self;
}
//重写dealloc
- (void)dealloc
{
[_engine release];
NSLog(@"%@ was dealloc!",self);
[super dealloc];
}
@end
Engine:
@implementation Engine
//重写dealloc
- (void)dealloc
{
NSLog(@"%@ was dealloc!",self);
[super dealloc];
}
@end