OC内存管理的一些研究

1.内存分配 静态区 栈区 堆区

  • 静态区: 1.代码区 2.初始化区 (初始化的全局变量和静态变量)3.未初始化区(未初始化的全局变量和静态变量)
  • 栈区:由编译器自动分配并释放,存放函数的参数值,局部变量等。栈是系统数据结构,线程之间栈控件是不共享的。优点是快速高效,缺点时有限制,数据不灵活。栈区地址从高到低分配;[先进后出]
  • 堆区:比较灵活,动态分配和释放,堆中的对象都是以指针来访问的,指针从线程栈中来,但不独属于某个线程,堆也是对复杂的运行时处理的基础支持,还有就是ARC还是MRC、“谁分配谁释放”说的都是堆上对象的管理,堆区的地址是从低到高分配;

2.内存管理(堆区内存)

引用计数机制:

3.内部实现原理

对象调用alloc方法实际上内部调用了 + (instancetype)allocWithZone:(struct _NSZone *)zone方法, allocWithZone 调用NSAllocateObject(类,,)

retainCount ,retain ,release方法实际调用的是CoreFondation框架中的_CFDoExternRefOperation(OPERATION_retainCount,self)

_CFDoExternRefOperation(OPERATION_retain,self)

_CFDoExternRefOperation(OPERATION_release,self)

苹果是采用散列表(引用计数表)的形式来管理引用计数

4.autorelease工作原理

//四种写法

1.通过类方法addObject

//    NSAutoreleasePool* pool=[NSAutoreleasePool new];

//   

//    person* per1=[person new];

//    [NSAutoreleasePool addObject:per1];

//    [pool drain];

2.通过实例方法addObject

   //2

//    NSAutoreleasePool* pool=[NSAutoreleasePool new];

//   

//    person* per1=[person new];

//    [pool addObject:per1];

//    [pool drain];

3.通过autorelease方法

NSAutoreleasePool* pool=[NSAutoreleasePool new];

   

    person* per1=[person new];

    [per1 autorelease];

    [pool drain];

//4.

 @autoreleasepool {

    person* per1=[person new];

    [per1 autorelease];

    }

autorelease实例方法本质就是调用NSAutoreleasePool对象的addObject方法;

iOS 内部实现

objc_autoreleasePoolPush() 等同于NSAutoreleasePool* pool=[NSAutoreleasePool new];

objc_autorelease(per1) 等同于[per1 autorelease];

objc_autoreleasePoolPop(pool) 等同于[pool drain];

4.ARC规则

1.不能使用retain/release/retainCount/autorelease

内存管理是编译器的工作,因此没有必要使用retain/release/retainCount/autorelease方法,编译器会在适当的时候插入这些方法

2.不要显式调用dealloc

3.arc环境四个修饰符 __weak __strong __autoreleasing __unsafe_unretained

__strong 修饰的对象为强引用 对象默认的是__strong修饰符

__weak 修饰的对象为弱引用 

__unsafe__unretained 不安全的所有权修饰符,符有__unsafe__unretained修饰符的变量不属于编译器的内存管理对象。

__autoreleasing 在ARC下代替autorelelease的工作,将变量赋值给符有__autoreleasing修饰符的变量 和在MRC下对象调用autorelease方法同理。

理解:

  • 在ARC环境中,使用cory alloc new mutable copy 生成的对象,编译器会帮助我们添加release 使用 [NSMutableArray array]诸如此类的方法生成的对象 编辑器会把对象注册到autoreleasePool 中。
  • 在访问__weak修饰符的变量时,实际上必定要访问注册在autoreleasePool中的对象。

4.规则

alloc 实际上是调用NSAllocateObject 但是在ARC下禁止使用

init 开头的方法必须是实例方法并且必须要返回对象,返回的类型可以是id类型或该方法声明类的对象类型

5属性

5.1在ARC下属性关键字与所有权修饰符的关系

5.2 在类中声明的实例变量和同一个属性 所有权修饰符必须一致,否则报错

例如:

{

    id  obj;

}

@property(nonatomic,weak)id obj; 编译报错

6数组

在内存管理方面,静态数组与可变数组的区别:

静态数组:编译器能够根据变量的作用域自动插入释放赋值对象的代码。

可变数组:编译器不能确定数组的生存周期,无法插入释放内存的代码,所以对可变数组来讲,一定要先使可变数组中每个元素强引用失效,再去废弃内存块。

 ARC的实现

1__strong修饰符

//1.new alloc 等创建的对象实现过程

{

id __strong obj=[NSObject new];

//内部实现

id obj=objc_msgSend(NSObject,@selectot(alloc));

objc_msgSend(obj,@selector(init));

//变量作用域结束时 释放

objc_release(obj);

}

//2. 通过alloc new copy 方法之外的实现例如 array方法

{

id __strong obj6=[NSMutableArray array];

//内部实现

id  obj6=objc_msgSend(NSMutableArray,@selector(array));

objc_retainAutoreleasedReturnValue(obj);

objc_release(obj);

+(id)array{

id  obj6=objc_msgSend(NSMutableArray,@selector(alloc));

objc_msgSend(obj,@selector(init));

return objc_autoreleaseReturnValue(obj);

}

}

2.__weak 修饰符 

  1. __weak修饰符修饰的变量所引用的对象被废弃,则将nil赋值给变量。
  2. __weak修饰符的变量,即是使用注册在autoreleasePool中的对象。

2.1验证1

{

//obj1附加__strong修饰符并已经被对象赋值

id __weak obj1=obj;

//编译器模拟代码

id obj1;

objc_initWeak(&obj1,obj);

objc_destroyWeak(&obj1);

//id obj1;

obj1=0;

objc_storeWeak(&obj1,obj);

objc_storeWeak(&obj1,0);

}

objc_storeWeak函数把第二参数的赋值对象的地址作为键值,将第一参数符有weak修饰符的变量的地址注册到weak表中,如果第二个参数为0,则把变量的地址从weak表中删除,

将废弃的对象的地址作为键值进行检索,查询出对应的附有__weak修饰符的变量的地址,对于一个键值,可以注册多个变量的地址。

在对象被销毁时内部实现的过程是1.objc_release 2.引用计数为0所以执行dealloc 3._objc_rootDealloc 4.object_dispose 5.objc_destructInstance 6.objc_clear_deallocating 在调用.objc_clear_deallocating函数时内部实现是1.从weak表中获取废弃对象的地址为键值得记录 2.将包含在记录中的所有附有__weak修饰符变量的地址,赋值为nil,3.从weak表中删除该记录,4.从引用计数表中删除废弃对象的地址为键值得记录。

ex:

 id  obj8=[NSObject new];

    id __weak obj9=obj8;

    NSLog(@"obj===%@",obj9);输出obj===<NSObject: 0x60800001e740>

/**************************************/

 id __weak obj8=[NSObject new];

  NSLog(@"obj===%@",obj8);输出obj===(null)

/*

*/

2.验证2

{

//obj 是__strong 修饰符切已被赋值的变量

id __weak obj1=obj;

NSLog(@“%@“,obj1);

}

上述代码可以转换为如下形式:

id obj1;

objc_initWeak(&obj1,obj);

id tmp=objc_loadWeakRetained(&obj1);

objc_autorelease(tmp);

NSLog(@“%@“,tmp);

objc_destroyWeak(&obj1);

objc_loadWeakRetained($obj1)函数取出__weak 修饰符的obj1所引用的对象并retain操作,

objc_autorelease(tmp)将tmp变量注册进入释放池中。

3.__autoreleasing 修饰符

将对象赋值给附有__autoreleasing修饰符的变量等同于MRC下给对象发送autorelease消息,

猜你喜欢

转载自blog.csdn.net/qq_28117621/article/details/83995290