内存布局
- IOS的内存布局除了我们知道的内存五大区,还有内核区和保留区,我们知道虚拟内存分配了4GB的空间,前面3GB分配给了保留区和五大区,剩下的1GB是给内核区使用的
- 内核区是用来给系统内核操作处理的区域,保留区是给系统处理nil等
- 内存五大区的介绍内存五大区
内存管理方案
ARC和MRC
- 在早期的苹果系统里面是需要我们手动管理内存的,手动内存管理遵循谁创建,谁释放,谁引用,谁管理的原则
- IOS5之后苹果引入了ARC(自动引用计数),ARC是一种编译器特性,只是编译器在对应的时间给我们插入了内存管理的代码,其本质还是按照MRC的规则
TaggedPointer
- 小对象处理方案,苹果会对NSNumber、NSDate、小NSString进行处理,小对象的值会存储在常量区,有系统分配管理内存,并且能通过地址直接看到对应的值,在
objc
源码的_read_images
会调用initializeTaggedPointerObfuscator
方法对小对象进行处理,在ios12之后会对小对象进行混淆处理,打印地址将不能直接看到小对象的值。
static void
initializeTaggedPointerObfuscator(void)
{
if (sdkIsOlderThan(10_14, 12_0, 12_0, 5_0, 3_0) ||
// Set the obfuscator to zero for apps linked against older SDKs,
// in case they're relying on the tagged pointer representation.
DisableTaggedPointerObfuscation) {
objc_debug_taggedpointer_obfuscator = 0;
} else {// 在高于上面的版本做了 objc_debug_taggedpointer_obfuscator 混淆
// Pull random data into the variable, then shift away all non-payload bits.
arc4random_buf(&objc_debug_taggedpointer_obfuscator,
sizeof(objc_debug_taggedpointer_obfuscator));
objc_debug_taggedpointer_obfuscator &= ~_OBJC_TAG_MASK;
}
}
小对象的内存管理
- 运行下面这段代码
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self taggedPointerMemoryManagement];
}
- (void)taggedPointerMemoryManagement
{
for (int i = 0; i < 5000; i++) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
self.testStr = [NSString stringWithFormat:@"test"];
NSLog(@"%@",self.testStr);
});
}
}
- (void)nonTaggedPointerMemoryManagement
{
for (int i = 0; i < 5000; i++) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
self.testStr = [NSString stringWithFormat:@"test-长一点的字符串"];
NSLog(@"%@",self.testStr);
});
}
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[self nonTaggedPointerMemoryManagement];
}
- 发现一个如下现象,当我们点击屏幕执行
nonTaggedPointerMemoryManagement
,会出现崩溃如下
- 原因是多线程调用release引起的,但是为什么
taggedPointerMemoryManagement
方法没有崩溃了呢,原因是两个字符串类型不一样。
- 通过源码知道,对象在retain和release的时候对taggedpointed对象没有处理,所以不会有多线程release造成的崩溃
id
objc_retain(id obj)
{
if (!obj) return obj;
if (obj->isTaggedPointer()) return obj;
return obj->retain();
}
void
objc_release(id obj)
{
if (!obj) return;
if (obj->isTaggedPointer()) return;
return obj->release();
}
判断小对象
- 代码调用顺序
objc_object::isTaggedPointer()
->_objc_isTaggedPointer(const void * _Nullable ptr)
inline bool
objc_object::isTaggedPointer()
{
return _objc_isTaggedPointer(this);
}
static inline bool
_objc_isTaggedPointer(const void * _Nullable ptr)
{
return ((uintptr_t)ptr & _OBJC_TAG_MASK) == _OBJC_TAG_MASK;
}