为了开学的面试,就在博客里总结一下面试会问到的问题,今天就来谈谈内存管理,看到一篇文章非常不错,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 (0);
} // main

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

int main (int argc, const char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int i, j;
for (i = 0; i < 100; i++ )
{for (j = 0; j < 100000; j++ )[NSString stringWithFormat:@"1234567890"];//产生的对象是autorelease的。
}
[pool release];
return (0);
} // 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 = 0; i < 100; i++ )
{NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];for (j = 0; j < 100000; j++ )[NSString stringWithFormat:@"1234567890"];//产生的对象是autorelease的。[loopPool release];
}
[pool release];
return (0);
} // main

转载于:https://www.cnblogs.com/yueyingsuixing/p/3457767.html

IOS面试_1.浅析内存管理相关推荐

  1. 理解 iOS 和 macOS 的内存管理

    在 iOS 和 macOS 应用的开发中,无论是使用 Objective-C 还是使用 swift 都是通过引用计数策略来进行内存管理的,但是在日常开发中80%(这里,我瞎说的,8020 原则嘛?)以 ...

  2. 关于IOS的多任务以及内存管理

    看了很多FY为自己的可用内存是350MB还是380MB纠结.为了多优化出一点可用内存费脑筋.  IOS的任务管理和内存管理,跟windows是有很大差别的.很多FY习惯于用 windows的思维去看待 ...

  3. 内存管理 浅析 内存管理/内存优化技巧

    内存管理 浅析 下列行为都会添加一个app的内存占用: 1.创建一个OC对象: 2.定义一个变量: 3.调用一个函数或者方法. 假设app占用内存过大.系统可能会强制关闭app,造成闪退现象,影响用户 ...

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

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

  5. iOS之深入解析内存管理Tagged Pointer的底层原理

    一.前言 ① Tagged Pointer 概念 iOS 开发者对"引用计数"这个名词肯定不陌生,引用计数是苹果为了方便开发者管理内存而引入的一个概念.当引用计数为 0 时,对象就 ...

  6. linux c 将虚拟地址转化为物理地址_面试不懂 Linux 内存管理?我用 20 张图给你讲明白...

    微信搜索公众号「 后端技术学堂 」回复「1024」获取50本计算机电子书,回复「学习路线」获取超详细后端技术学习路线思维导图,文章每周持续更新,我们下期见! 大家好,我是柠檬哥. 分享编程学习,助力程 ...

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

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

  8. iOS底层原理之内存管理

    文章目录 定时器 CADisplayLink.NSTimer GCD定时器 内存管理 iOS程序的内存布局 Tagged Pointer OC对象的内存管理 拷贝 引用计数的存储 dealloc 自动 ...

  9. iOS 闪退与内存管理

    先说闪退是什么,闪退就是程序崩溃了,原因多种多样,内存不足是一种,大部分是因为程序本身有BUG(BUG中野指针类居多,建议百度下野指针,能看懂的就看懂了,看不懂的就不解释了,几句话说不清楚) 讲一个概 ...

最新文章

  1. Ubuntu中用户名密码和root密码修改
  2. Changes at Different Environment?
  3. 到华为去,到AI最前沿去~ 华为杭州研究所欢迎您!
  4. linux5中文支持,centos安装中文支持
  5. 如何用木板做桥_为这份动手能力点赞!旧木板打磨后做成橱柜,效果可媲美定制的...
  6. echarts树图节点垂直间距_铝模板的安装、拆除、节点、禁止做法详解
  7. 别天天看看直播了,你知道如何用jmeter对直播间做压测吗
  8. Android Studio导入从Github下载的源码
  9. 新软件--AutoReply(自动回复),还能自动接听,做答录机
  10. java web个人博客开发(一需求获取和需求分析文档)
  11. Wireshark软件的使用教程
  12. IP地址被屏蔽怎么解决
  13. 省市县GDP、地级市三大产业产值数据、农业GDP相关数据
  14. FAQ:The field file exceeds its maximum permitted size of 1048576 bytes.
  15. 诞生11年,入华9年,今年的智慧城市会更好吗?
  16. RobotStudio安装步骤
  17. 重新“推开世界的门”:4年过去了,VR还能复兴吗?
  18. WeChatDeveloper
  19. 听说C语言很难?怎么不来看看我这篇(二)变量
  20. 阴阳师系统转移开放服务器,阴阳师:运营商倒闭后?原来只是子账号数据转移,可迁移到官服...

热门文章

  1. Firefox 扩展开发 install.rdf和chrome.manifest
  2. 利用redis漏洞远程添加计划任务挖取比特币
  3. Activt工作流数据库对应表的作用
  4. TOMCAT startup.bat
  5. 动态产生一个TextBox,并使输入的文本靠右对齐
  6. [原创].NET 业务框架开发实战之十 第一阶段总结,深入浅出,水到渠成(前篇)...
  7. Sms中关于操作系统的部署之上
  8. Python爬虫(七)_非结构化数据与结构化数据
  9. RMQ(Range Minimum/Maximum Query)问题:
  10. LeetCode 106. 从中序与后序遍历序列构造二叉树(Construct Binary Tree from Inorder and Postorder Traversal)...