内存布局与内存管理方案

146 阅读2分钟

内存布局

保留区

  • 预留给系统处理nil等
  • **0x00400000**开始

代码段

  • 编译之后的代码

数据段

  • 字符串变量
  • 全局变量
  • 静态变量

  • alloc
访问堆区内存时,一般是先通过对象读取到对象所在的栈区的指针地址,然后通过指针地址访问堆区

  • 局部变量
  • 函数参数
内存从高到底分配 内存是连续的

内核区

  • 系统用来进行内核处理操作的区域

具体内存布局👇

内存管理方案

ARC

MRC

Tagged Pointer

  • 小对象是不会进行retain和release操作的 因此不用担心过度释放问题

  • 专门用来处理小对象,例如NSNumber、NSDate、小NSString等

  • NSTaggedPointerString类型,存在常量区

  • 1.NSTaggedPointerString:标签指针,是苹果在64位环境下对NSString、NSNumber等对象做的优化。对于NSString对象来说

    • 字符串是由数字、英文字母组合且长度小于等于9时,会自动成为NSTaggedPointerString类型,存储在常量区
    • 当有中文或者其他特殊符号时,会直接成为__NSCFString类型,存储在堆区
  • 2.__NSCFString:是在运行时创建的NSString子类,创建后引用计数会加1存储在堆上

  • 3.__NSCFConstantString字符串常量,是一种编译时常量retainCount值很大,对其操作,不会引起引用计数变化,存储在字符串常量区

64bit开始,iOS引入了Tagged Pointer技术,用于优化NSNumberNSDateNSString等小对象的存储

在没有使用Tagged Pointer之前, NSNumber等对象需要动态分配内存、维护引用计数等,NSNumber指针存储的是堆中NSNumber对象的地址值

使用Tagged Pointer之后,NSNumber指针里面存储的数据变成了:Tag + Data,也就是将数据直接存储在了指针中

当指针不够存储数据时,才会使用动态分配内存的方式来存储数据

objc_msgSend能识别Tagged Pointer,比如NSNumber的intValue方法,直接从指针提取数据,节省了以前的调用开销

如何判断一个指针是否为Tagged Pointer?
iOS平台,最高有效位是1(第64bit)  16进制转为2进制

isTaggerPointer 

pointer & 1

Mac平台,最低有效位是1

DEMO

崩溃原因是多条线程同一个对象进行释放,导致对象过度释放,所以才会崩溃。