复习C语言中的内存:
int *p = malloc(8); —>堆内存
free(p);
free(p); —>过度释放
- 内存溢出: 内存不释放
- 野指针: free之后还可以用p找到那块内存, 因为是标记删除; 但内存中内容不能保证还是原来的, 因为所有权已还给系统
野指针异常是程序crash主要原因
将ARC改为MRC:
- ARC Automatic Reference Counting 自动引用计数
- MRC Manual Reference Counting 手动引用计数
- 关闭ARC就是MRC
- ARC是基于MRC的
内存管理:
1. - retainCount: 打印当前对象的引用计数, 结果只能作为一个参考
2. + alloc: 开辟内存空间,让被开辟的内存空间引用计数变为1, 这是由0到1的过程
Person
*person1 = [[Person
alloc]
init];
此时 person1 引用计数由0变为1
NSLog(@"%lu", [person1
retainCount]);
打印结果:
1
3. - retain: 引用计数+1
[person1
retain];
[person1
retain];
person1 引用计数两次 +1
NSLog(@"%lu", [person1
retainCount]);
打印结果: 3
4. - release: 引用计数-1,
而不是释放
[person1
release];
person1引用计数 -1
NSLog(@"%lu", [person1
retainCount]);
打印结果: 2
[person1
release];
NSLog(@"%lu", [person1
retainCount]);
打印结果: 1
[person1
release];
NSLog(@"%lu", [person1
retainCount]);
打印结果: 1(*为何是1而不是0?)
[person1
release];
过多的释放,会导致crash
内存的所有权:
所有权是管理内存的根本性的问题, 一个指针能不能对内存进行release, 就看有没有所有权.
只有开辟空间的对象才拥有内存的所有权.
5. - autorelease: 出自动释放池 (
@autoreleasepool
{}) 时-1
|
Person
*person2 = [[Person
alloc]
init];
@autoreleasepool
{
[person2
retain];
[person2
retain];
[person2
release];
[person2
autorelease];
[person2
autorelease];
// [person2 autorelease]; —>同样会造成过度释放
NSLog(@"%lu", [person2
retainCount]);
打印结果:
2
} —> 在出释放池,运行释放池后第一个语句之前会执行dealloc
NSLog(@"%lu", [person2
retainCount]);
打印结果: 1
|
6. - dealloc: 释放内存, 当对象的引用计数变为0的时候, 系统会自动调用dealloc方法, 可以重写父类的dealloc方法, 重写时不用声明,
不能手动调用.
在类中重写dealloc方法:
|
- (void)dealloc{
[_name
release]; —> 将由成员变量指向的内存空间的引用计数-1. 基本数据类型的成员变量不需要release, 因为在栈区, 由系统自动管理
[_sex
release];
[super
dealloc];
}
|
调用父类的dealloc方法,释放公共部分的属性和成员变量,
[super
dealloc]; 作为方法的最后一句.
7. - copy: 会开辟一段内存空间, 和原来大小一致, 存储内容一致, 会保持原来的引用计数不变,
新的内存引用计数变为1. 遵循NSCopying协议才能使用copy.
想要使自己创建的Person类使用copy方法:
1. 签订NSCopying协议:
@interface Person :
NSObject<NSCopying>
2. 在.h文件中实现NSCopying协议中声明的方法:
- (id)copyWithZone:(NSZone
*)zone;
|
- (id)copyWithZone:(NSZone
*)zone{
NSZone, 内存池, 里面的内存都是没用过的
Person *p = [[Person
allocWithZone:zone]
init];
使用拷贝区zone, 创建一个新的对象, 相当于开辟空间, 并初始化
p.name
=
self.name;
p.sex =
self.sex;
把对象自己的属性内容给新的对象拷贝一份
return p;
}
|
3. 使用copy方法:
Person *person8 = [person7
copy];
*关于release方法的实现:
|
系统不让重写release方法, 此处仅为演示:
//- (void)release{
// // if (self.retainCount == 1) {
//// self.retainCount—; —>当引用计数为1的时候调用release,目的为将内存还给系统,所以没有必要再-1了,直接释放内存即可
// [self dealloc];
// }else{ // self.retainCount--; // } //}
|
内存管理的原则:
- 当看到alloc, retain, copy时, 要写release, 要保证引用计数的加减平衡
- 如果但不到, 则不管
说明:
引用计数的变化针对的是内存空间,
而不是指针变量.
|
Person *person001 = [[Person
alloc]
init];
NSLog(@"%lu", [person001
retainCount]); —> 打印结果:
1
[person001
retain];
[person001
retain];
NSLog(@"%lu", [person001
retainCount]); —> 打印结果:
3
Person
*person002 = person001;
NSLog(@"%lu", [person002
retainCount]);
—> 打印结果: 3
此时person002 与 person001 指的是同一块内存空间
[person002
release];
NSLog(@"%lu", [person001
retainCount]);
—> 打印结果:
2
当对person2进行release操作时, 使用person001调用retainCount打印出的结果同样会-1
|
数组的内存管理:
|
Person
*person3 = [[Person
alloc]
init];
NSMutableArray
*arr = [NSMutableArray
array];
[arr
addObject:person3];
NSLog(@"%lu, %lu", [arr
retainCount], [person3
retainCount]);
打印结果:
1, 2
[arr
removeObject:person3];
NSLog(@"%lu", [person3
retainCount]);
打印结果:
1
|
被加入到数组中的元素会被retain一次.
当元素被移除的时候,元素会被release一次.
1482

被折叠的 条评论
为什么被折叠?



