ios 怎么判断字符串的字节数_IOS-内存管理

内存布局

  • IOS的内存布局除了我们知道的内存五大区,还有内核区和保留区,我们知道虚拟内存分配了4GB的空间,前面3GB分配给了保留区和五大区,剩下的1GB是给内核区使用的

8dbf1078c74228683fc2a89f13625732.png
  • 内核区是用来给系统内核操作处理的区域,保留区是给系统处理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,会出现崩溃如下

2ce4a6d2526e0dc855140de7f1cc4f42.png
  • 原因是多线程调用release引起的,但是为什么taggedPointerMemoryManagement方法没有崩溃了呢,原因是两个字符串类型不一样。

6bfa1a18bfdfa487139f8b482e1c8197.png

d6a5cd9cd2ed02458964421de4efa88b.png
  • 通过源码知道,对象在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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值