为了开学的面试,就在博客里总结一下面试会问到的问题,今天就来谈谈内存管理,看到一篇文章非常不错,http://vinceyuan.cnblogs.com/,深入浅出,推荐大家去看看!

  Objective-C使用一种(Retain Count)引用计数的机制来管理内存,在OC中,每个对象都持有自己的retain count,引用计数可以理解为就是一个计数器,当对象alloc创建的时候,会自动设置为1,当给对象发送retain消息的时候,引用计数会加1,当给对象发送release消息的时候,引用计数会减1,当引用计数为0的时候,对象会释放所占用的内存,这就是内存管理的机制,听起来比较容易吧,下面就进一步分析这种机制。

  首先,我们应该知道为什么要这样做?我们经常在不同的对象中引用相同的对象,例如:假设我们用不同电脑远程连接到同一台服务器进行远程操作,转化成OC语言就是不同电脑对象引用相同的服务器对象,这时候有一台电脑在服务器上敲了shutdown命令,让服务器挂掉了,这时候我们所有电脑都连接不上去了,其他人就工作不了了,引用计数其实就像一个计数开关,只有当没有电脑连接的时候,计数为0,才允许执行shutdown命令(非常理想状态下,现实中可不要这样做)。

  不同于java的GC回收机制,java中当没有对象引用指向原先分配给某个对象的内存时,该内存便成为垃圾。JVM的一个系统级线程会自动释放该内存块,除了释放没用的对象,垃圾回收也可以清除内存记录碎片。由于创建对象和垃圾回收器释放丢弃对象所占的内存空间,内存会出现碎片。碎片是分配给对象的内存块之间的空闲内存洞。碎片整理将所占用的堆内存移到堆的一端,JVM将整理出的内存分配给新的对象。OC中这种特有的retain count机制,给我们更多权限,让开发者去控制对象释放的时间以及如何去释放,所以我们得更加小心,过早的释放内存,可能会引起程序崩溃,长时间不释放占用的内存,程序在运行一段时间后可能会发生内存泄露。

  Objective-C采用了引用计数(retain count)。对象的内部保存一个数字,表示被引用的次数。例如,某个对象被两个指针所指向(引用)那么它的retain count为2。需要销毁对象的时候,不直接调用dealloc,而是调用release。release会让retain count减1,只有retain count等于0,系统才会调用dealloc真正销毁这个对象。

        ClassA *obj1 = [[ClassA alloc] init];//对象生成时,retain count = 1

        [obj1 release]; //release使retain count减1,retain count = 0,dealloc自动被调用,对象被销毁
        

 下面观看一个例子

ClassA *obj1 = [[ClassA alloc] init]; //retain count = 1
ClassA *obj2 = obj1; //retain count = 1
[obj1 hello]; //输出hello
[obj1 release]; //retain count = 0,对象被销毁
[obj2 hello];
[obj2 release];

obj2引用了obj1,此时retain count为1,当obj1执行完消息释放后,retain count=0,此时obj2变成了无效指针,这里再执行[obj2 release]会引起内存的过度释放

所以一定要谨记,不是alloc创建,而是指针赋值的时候,一定要retain,拿到对象的所有权

ClassA *obj1 = [[ClassA alloc] init]; //retain count = 1
ClassA *obj2 = obj1; //retain count = 1
[obj2 retain]; //retain count = 2
[obj1 hello]; //输出hello
[obj1 release]; //retain count = 2 – 1 = 1
[obj2 hello]; //输出hello
[obj2 release]; //retain count = 0,对象被销毁

这样写的确可以解决问题,但是如果对象非常多得时候,这样的操作会不会太繁琐了点,有没有简单一点的解决办法?所以oc引入了自动释放池autorelease pool,这也不同于java的全自动垃圾回收

新生成的对象调用autorelease就可以了

ClassA *obj1 = [[[ClassA alloc] init] autorelease]; //retain count = 1 但无需调用release

如果存在指针赋值,与上面的代码也相似

ClassA *obj1 = [[[ClassA alloc] init] autorelease]; //retain count = 1
ClassA *obj2 = obj1; //retain count = 1
[obj2 retain]; //retain count = 2
[obj1 hello]; //输出hello
//对于obj1,无需调用(实际上不能调用)release
[obj2 hello]; //输出hello
[obj2 release]; //retain count = 2-1 = 1

这里有个有趣的问题,retain count不是1么,还不能销毁呀,什么时候才能销毁呢?

所以我们得了解一下autorelease pool的原理机制。

1)autorelease pool不是天生的,需要手动创立。只不过在新建一个iphone项目时,xcode会自动帮你写好。autorelease pool的真名是NSAutoreleasePool。

  

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

2)NSAutoreleasePool内部包含一个数组(NSMutableArray),用来保存声明为autorelease的所有对象。如果一个对象声明为autorelease,系统所做的工作就是把这个对象加入到这个数组中去。

ClassA *obj1 = [[[ClassA alloc] init] autorelease]; //retain count = 1,把此对象加入autorelease pool中

3)   NSAutoreleasePool自身在销毁的时候,会遍历一遍这个数组,release数组中的每个成员。如果此时数组中成员的retain count为1,那么release之后,retain count为0,对象正式被销毁。如果此时数组中成员的retain count大于1,那么release之后,retain count大于0,此对象依然没有被销毁,内存泄露。

那是不是有了自动释放池autorelease pool就万无一失了,其实不然

默认只有一个自动释放池

int main (int argc, const char *argv[])
{
NSAutoreleasePool *pool;
pool = [[NSAutoreleasePool alloc] init]; // do something [pool release];
return ();
} // main

所有标记为autorelease的对象在这个pool内被销毁,但是如果这个自动释放池里面含有大量autorelease的对象,还是容易造成内存不足的情况,比如说:

int main (int argc, const char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int i, j;
for (i = ; i < ; i++ )
{
for (j = ; j < ; j++ )
[NSString stringWithFormat:@""];//产生的对象是autorelease的。
}
[pool release];
return ();
} // main

这种情况,大量内存被占用,只有poll销毁的时候,那些声明为autorelease对象才被销毁,这对于ios程序来说并不乐观,iphone内存本身有限,那有没有更好的解决办法,所以我们可以用autorelease嵌套机制来控制。

Objective-C程序中可以嵌套创建多个autorelease pool。在需要大量创建局部变量的时候,可以创建内嵌的autorelease pool来及时释放内存。

int main (int argc, const char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int i, j;
for (i = ; i < ; i++ )
{
NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];
for (j = ; j < ; j++ )
[NSString stringWithFormat:@""];//产生的对象是autorelease的。
[loopPool release];
}
[pool release];
return ();
} // main

iOS面试_1.浅析内存管理的更多相关文章

  1. iOS技术面试02:内存管理

    怎么保证多人开发进行内存泄露的检查. 如何定位内存泄露? 1> 使用Analyze进行代码的静态分析(检测有无潜在的内存泄露) 2> 通过leak检查在程序运行过程中有无内存泄露 3> ...

  2. IOS 非ARC开发内存管理的几条规则

    关于ios内存管理.在开发过程中,内存管理很重要,我简单说明一下. 1.正确用法 UIView *v = [[UIView alloc] init]; //分配后引用计数为1 [self.view a ...

  3. iOS 下ARC的内存管理机制

    本文来源于我个人的ARC学习笔记,旨在通过简明扼要的方式总结出iOS开发中ARC(Automatic Reference Counting,自动引用计数)内存管理技术的要点,所以不会涉及全部细节.这篇 ...

  4. iOS性能优化之内存管理:Analyze、Leaks、Allocations的使用和案例代码

    最近接了个小任务,和公司的iOS小伙伴们分享下instruments的具体使用,于是有了这篇博客...性能优化是一个很大的话题,这里讨论的主要是内存泄露部分. 一. 一些相关概念 很多人应该比较了解这 ...

  5. IOS基础之 (十一) 内存管理 ARC

    一 内存管理 1. set 方法内存管理的相关参数 retain: release旧值,retain新值(值适用于OC对象) assign:直接赋值(set方法默认,适用于非OC对象类型,即基本数据类 ...

  6. iOS中引用计数内存管理机制分析

    在 iOS 中引用计数是内存的管理方式,虽然在 iOS5 版本中,已经支持了自动引用计数管理模式,但理解它的运行方式有助于我们了解程序的运行原理,有助于 debug 程序. 操作系统的内存管理分成堆和 ...

  7. IOS基础 Day-1手动内存管理

    辞职回家打算自学IOS开发,就在借个地方记录一下 Day-1      手动内存管理                   主要内容:release  retain必须配对好,不然会占用内存 慢慢积累导 ...

  8. iOS 非ARC基本内存管理系列 -手把手教你ARC——iOS/Mac开发ARC入门和使用(转)

    手把手教你ARC——iOS/Mac开发ARC入门和使用 Revolution of Objective-c 本文部分实例取自iOS 5 Toturail一书中关于ARC的教程和公开内容,仅用于技术交流 ...

  9. iOS 非ARC基本内存管理系列 2-多对象内存管理(3) 利用@property来自动管理内存

    iOS 基本内存管理-多对象内存管理(2)中可以看到涉及到对象的引用都要手动管理内存:每个对象都需要写如下代码 // 1.对要传入的"新车"对象car和目前Person类对象所拥有 ...

随机推荐

  1. 51nod K 汽油补给 大根堆+小根堆....

    题目传送门 用优先队列瞎搞... 想着在每个地方 先算上一个点到这一个点要花费多少钱 这个用小根堆算就好 然后在这个地方加油 把油钱比自己多的替代掉 这个用大根堆维护一下 然后两个堆之间信息要保持互通 ...

  2. [object-c 2.0 程序设计]object-c review (一)

    // // main.m // cmdTry // // Created by Calos Chen on 2017/8/21. // Copyright © 2017年 Calos Chen. Al ...

  3. 【Mysql优化】聚簇索引与非聚簇索引概念

    必须为主键字段创建一个索引,这个索引就是所谓的"主索引".主索引与唯一索引的唯一区别是:前者在定义时使用的关键字是PRIMARY而不是UNIQUE.  首先明白两句话: innod ...

  4. LeetCode 151 reverse word in a string

    Given an input string, reverse the string word by word. For example, Given s = "the sky is blue ...

  5. Linux-进程间通信(一): 管道

    1. 管道局限性: (1) 半双工:(若模拟全双工,可以使用两个管道,即,proc1-->proc2一条管道,proc2-->proc1一条管道) (2) 只能在具有公共祖先的进程之间使用 ...

  6. flask传参到jinja2模板出现&#39;导致不可用

    http://blog.csdn.net/wangqing008/article/details/48437793 经常会有字符 空格 ' "" 等被转义成其他字符,这其实是特殊字 ...

  7. python中的迭代器详解

    #原创,转载请先联系 理论性的东西有点枯燥,耐心点看- 1.迭代是什么? 我们知道可以对list,tuple,dict,str等数据类型使用for...in的循环语法,从其中依次取出数据,这个过程叫做 ...

  8. 使用bottle进行web开发(9):文件上传;json传递

    1.文件上传 如果要完成文件上传,则需要对上文的form做一点改动,具体如下: <form action="/upload" method="post" ...

  9. Mysql中大表添加索引的办法

    Hash索引与 Btree索引的区别http://database.51cto.com/art/201010/229525.htm Creating Indexes/Sorting on very l ...

  10. <context-param>与<init-param>的区别与作用(转自青春乐园)(

    <context-param>的作用:web.xml的配置中<context-param>配置作用1. 启动一个WEB项目的时候,容器(如:Tomcat)会去读它的配置文件we ...