内存布局
1782258-c982ebeacd0a42dc.png- 栈(stack):方法调用,局部变量等,是连续的,高地址往低地址扩展
- 堆(heap):通过alloc等分配的对象,是离散的,低地址往高地址扩展,需要我们手动控制
- 未初始化数据(bss):未初始化的全局变量等
- 已初始化数据(data):已初始化的全局变量等
- 代码段(text):程序代码
〜
MRC与ARC
MRC:
手动引用计数,手动添加retain, release
//MRC下的setter方法
- (void)setString:(NSString *)string{
if (_string != string) {
[string retain];
[_string release];
_string = string;
}
}
ARC:
自动引用计数,系统自动添加内存操作。但有些地方需要注意。
1.循环引用
block引起的循环引用,会强引用回调中使用的对象
NSTimer引起的循环引用,会强引用target
performSelector:afterDelay的问题,会强引用target,当方法一直没调用时,target会不能释放
2.NSNotification
通知的addObserver会建立一个弱引用到接收者,不会发生内存泄露的问题。但是我们需要在dealloc里面调用removeObserver,避免通知的时候,对象已经被销毁,这时候会发生crash.
参考:ARC下需要注意的内存管理
~
Copy协议
在iOS中并不是所有对象都支持Copy和MutableCopy,遵循NSCopying协议的类可以发送Copy协议,遵循NSMutableCopying协议的类可以发送MutableCopy消息。如果一个对象没有遵循这两个协议而发送Copy或者MutableCopy消息那么会发生异常。如果要遵循NSCopying协议,那么必须实现copyWithZone方法。
如果要遵循NSMutableCopying协议那么必须实现mutableCopyWithZone方法。
对于自定义对象来说调用Copy和MutableCopy方法都会重新分配一块内存。
// Man.h
#import <Foundation/Foundation.h>
@interface Man : NSObject<NSCopying,NSMutableCopying>
@property (nonatomic,strong)NSString *name;
@property (nonatomic,assign)NSInteger year;
@end
// Man.m
#import "Man.h"
@implementation Man
#pragma mark description方法内部不能打印self,不然会造成死循环
- (NSString *)description {
return [NSString stringWithFormat:@"[name = %@,year = %ld]", _name,_year];
}
//自定义深拷贝,实现copyWithZone方法
-(id)copyWithZone:(NSZone *)zone{
Man *newMan = [[[self class] allocWithZone:zone] init];
newMan.name = self.name;
newMan.year = self.year;
return newMan;
}
-(id)mutableCopyWithZone:(NSZone *)zone{
Man *newMan = [[[self class] allocWithZone:zone] init];
newMan.name = self.name;
newMan.year = self.year;
return newMan;
}
@end
//调用
Man *man = [[Man alloc]init];
man.name = @"张三";
man.year = 1;
Man *newMan = [man copy];
Man *newMutMan = [man mutableCopy];
~
weak
weak是Runtime维护了一个hash(哈希)表,用于存储指向某个对象的所有weak指针。weak表其实是一个hash(哈希)表,Key是所指对象的地址,Value是weak指针的地址(这个地址的值是所指对象指针的地址)数组。
__unsafe_unretained 与 weak 比较,__weak需要检查对象是否已经消亡,需要一些信息去跟踪对象的使用情况。也正因此,__unsafe_unretained 比 __weak快,当明确知道对象的生命期时,选择__unsafe_unretained 会有一些性能提升,而当情况不确定的时候,应该优先选用 __weak 。
参考:iOS内存管理(4)-引用计数的存储、weak原理
~
autoreleasepool
自动释放池,原理就不深究了,主要功能是让autorelease对象在释放池结束时才释放。
在ARC环境下使用的主要场景,在for循环alloc图片数据等内存消耗较大的场景。因为此时只有在for循环结束后(准确说是当前runloop结束后)才会释放临时对象,当入释放池后,能在每个循环结束时释放内存。
参考:iOS内存管理(5)-autorelease原理和autorelease和runloop的结合使用
网友评论