文明看博转载是对自己的尊重也是对学者的鼓励,欢迎讨论
-------------iOS-图说OC内存管理----------------
一.OC源代码分解及到C语言的讨论
int number;
1.上面的语句声明了一个int 类型的变量,这时候number的值是不确定的,number被编译器编译之后,number就是一个虚拟内存地址(可以想象,计算机资源这么宝贵,不可能去花空间来储存变量名的字符串,在源代码层面变量名是给人看的,在编译器的眼中任何的变量名,函数名,常量等都是虚拟地址)。int number=8;
2.这就相当于把8的值放到number的虚拟内存中去。number是值类型,如果它是在函数中的话,当函数执行完成后,它的生命周期就结束了会被释放,它的生命周期由它的作用域决定。typedef struct TestStruct{
int number;
}TestStrutType;
TestStrutType number;
number.number =8;
<p class="p1"><span class="s1">NSLog</span><span class="s2">(</span><span class="s3">@"number=%d number.number=%d"</span><span class="s2">,&number,&number.</span><span class="s4">number</span><span class="s2">);</span></p>
运行结果:
2015-01-17 15:33:33.575 MemoryManager[816:32368] number=1587763888 number.number=1587763888
3.声明一个结构体,用它来声明一个number变量,并设置number变量中的number成员的值为 8;被编译之后其实结构体变量number和其成员变量都在同一个虚拟内存中,它们也是值类型,生命周期由它的作用域决定,说白了就是函数调用返回决定。说到这里就得到一个结论,变量编译之后是一个虚拟内存地址,而变量的类型决定了去怎样读取它的值。
TestStrutType *number= malloc(sizeof(TestStrutType));
number->number =8;
4.声明一个TestStructType类型的指针变量number,并通过malloc手动分配对应类型大小的堆内存块,并把堆内存块的指针存放到栈上变量number指针变量的虚拟内存上,通过指针变量number给成员变量number赋值,这时候的数字8是存放在堆内存块中的。当number指针变量所在的函数返回,也就是number的生命周期结束了,通过malloc分配的内存块还在,它并没有被释放,这样就会造成内存泄漏。栈上的内存变量会自动释放,堆上的内存块是手动分配的就要手动释放,由于栈内存变量和堆内存块的管理机制不相同,这就引出了内存管理问题。
NSObject *obj = [[NSObject alloc]init];
5.声明一个NSObject类型的指针变量变量obj,指向一个NSObject类型的堆内存块。[[NSObject alloc]init]本质上就是调用malloc函数分配一个NSObject类型大小的内存块,并把它的堆内存虚拟地址赋值给栈上的指针变量obj,当obj所在的函数返回,也就是obj的生命周期结束了,这时obj被释放了,但是[[NSObject alloc]init]分配的堆内存块还在,这时就会出现内存泄漏的问题。由于堆内存的对象时手动释放,什么时候释放,什么时候不该释放,就成了编程中要考虑的问题,如果提前释放,当访问对象时就会报错,如果该释放的时候没有被释放,就会造成内存浪费。Object-C语言采用的是引用计数的方式来达到内存管理的。上面都只是问题的铺垫,下面我们将要了详细的对引用计数的内存管理全面的讲解。
在OC语言中最常用的语法格式是 (类型)*(指针变量) = ([[(类型)alloc]init])的形式来声明变量的。下面我分把它分解来说明。首先从等号分开。等号左边的是指针变量,等号右边的是该类型的实例内存块。等号左边的是在栈上的虚拟内存上,等号右边的是堆上的内存上。等号左边的变量是自动管理的,等号右边的内存块是要编程人要手动的管理的。下面我们就把OC的常用的表达式模拟成一个场景:打一个比方(等号的左边指针变量相当于一个人)(等号相当于把一根线交给人)(等号的右边相当于飘在空中的气球)(retain函数相当于retainCount加1)(release函数相当于retainCount 减1)(retainCount表示该气球是不是要被销毁掉,为0销毁,大于0保留),(autoReleasePool的变量相当于一个管理者)。于是通过上面的组合就得到下面的一些情景。
1.
NSObject *obj; //表示有一个人出现了,但是这个人并没有拉着气球
[[NSObject alloc]init]; //出现了一个气球,并没有任何人拉着它,但是它的retainCount为1所以它不能背销毁,(内存泄漏)
3.
NSObject *obj = [[NSObject alloc]init]; //obj这个人通过线拉着一个气球
4.
[[[NSObject alloc]init] retain]; //出现了一个没有线的气球,但是它的retainCount为2所以它不能背销毁,(内存泄漏)
5.
[[[NSObject alloc]init] release]; //刚创建就要被销毁的气球
NSObject *obj = [[NSObject alloc]init]; //obj这个人通过线拉着一个气球
[obj autorelease]; //obj这个人把气球的线交给了管理人员,retainCount不变,
7.
NSObject *obj = [[NSObject alloc]init]; //obj这个人通过线拉着一个气球
NSObject *obj2 = obj; //obj2这个人和obj这个人共用一根线共同的拉着个气球,retainCount不变
8.
NSObject *obj = [[NSObject alloc]init]; //obj这个人通过线拉着一个气球
NSObject *obj2 = [obj retain]; //obj2这个人和obj这个人用不同的线拉着同一个球,retainCount为2不变
9.
NSObject *obj = [[NSObject alloc]init]; //obj这个人通过线拉着一个气球
[obj release]; //obj把线减掉 retainCount减1,如果retainCount为0将会被销毁
待续。。。。。。。。。。。。。