李洪强iOS经典面试题37-解释垃圾回收的原理
李洪强iOS经典面试题37-解释垃圾回收的原理
问题
我们知道,Android 手机通常使用 Java 来开发,而 Java 是使用垃圾回收这种内存管理方式。 那么,ARC 和垃圾回收对比,有什么优点和缺点?
考查点
此题其实是考查大家的知识面,虽然做 iOS 开发并不需要用到垃圾回收这种内存管理机制。但是垃圾回收被使用得非常普遍,不但有 Java,还包括 JavaScript, C#,Go 等语言。
如果两个候选人,一个人只会 iOS 开发,另一个人不但会 iOS 开发,对别的语言或技术也有兴趣了解,那我通常更倾向于后者。而且事实常常是,由于后者对计算机兴趣更浓,他在 iOS 上也通常专研得比前者更多。
垃圾回收简介
作为 iOS 开发者,了解一下这个世界上除了 ARC 之外最流行的内存管理方式,还是挺有价值的。所以我尽量简单给大家介绍一下。
垃圾回收(Garbage Collection,简称 GC)这种内存管理机制最早由图灵奖获得者 John McCarthy 在 1959 年提出,垃圾回收的理论主要基于一个事实:大部分的对象的生命期都很短。
所以,GC 将内存中的对象主要分成两个区域:Young 区和 Old 区。对象先在 Young 区被创建,然后如果经过一段时间还存活着,则被移动到 Old 区。(其实还有一个 Perm 区,但是内存回收算法通常不涉及这个区域)
Young 区和 Old 区因为对象的特点不一样,所以采用了两种完全不同的内存回收算法。
Young 区的对象因为大部分生命期都很短,每次回收之后只有少部分能够存活,所以采用的算法叫 Copying 算法,简单说来就是直接把活着的对象复制到另一个地方。Young 区内部又分成了三块区域:Eden 区 , From 区 , To 区。每次执行 Copying 算法时,即将存活的对象从 Eden 区和 From 区复制到 To 区,然后交换 From 区和 To 区的名字(即 From 区变成 To 区,To 区变成 From 区)。
Old 区的对象因为都是存活下来的老司机了,所以如果用 Copying 算法的话,很可能 90% 的对象都得复制一遍了,不划算啊!所以 Old 区的回收算法叫 Mark-Sweep 算法。简单来说,就是只是把不用的对象先标记(Mark)出来,然后回收(Sweep),活着的对象就不动它了。因为大部分对象都活着,所以回收下来的对象并不多。但是这个算法会有一个问题:它会产生内存碎片,所以它一般还会带有整理内存碎片的逻辑,在算法中叫做 Compact。如何整理呢?早年用过 Windows 的硬盘碎片整理程序的朋友可能能理解,其实就是把对象插到这些空的位置里。这里面还涉及很多优化的细节,我就不一一展开了。
讲完主要的算法,接下来 GC 需要解决的问题就只剩下如何找出需要回收的垃圾对象了。为了避免 ARC 解决不了的循环引用问题,GC 引入了一个叫做「可达性」的概念,应用这个概念,即使是有循环引用的垃圾对象,也可以被回收掉。下面就给大家介绍一下这个概念。
当 GC 工作时,GC 认为当前的一些对象是有效的,这些对象包括:全局变量,栈里面的变量等,然后 GC 从这些变量出发,去标记这些变量「可达」的其它变量,这个标记是一个递归的过程,最后就像从树根的内存对象开始,把所有的树枝和树叶都记成可达的了。那除了这些「可达」的变量,别的变量就都需要被回收了。
听起来很牛逼对不对?那为什么苹果不用呢?实际上苹果在 OS X 10.5 的时候还真用了,不过在 10.7 的时候把 GC 换成了 ARC。那么,GC 有什么问题让苹果不能忍,这就是:垃圾回收的时候,整个程序需要暂停,英文把这个过程叫做:Stop the World。所以说,你知道 Android 手机有时候为什么会卡吧,GC 就相当于春运的最后一天返城高峰。当所有的对象都需要一起回收时,那种体验肯定是当时还在世的乔布斯忍受不了的。
看看下面这幅漫画,真实地展现出 GC 最尴尬的情况(漫画中提到的 Full GC,就是指执行 Old 区的内存回收):
当然,事实上经过多年的发展,GC 的回收算法一直在被优化,人们想了各种办法来优化暂停的时间,所以情况并没有那么糟糕。
答案
ARC 相对于 GC 的优点:
ARC 工作在编译期,在运行时没有额外开销。
ARC 的内存回收是平稳进行的,对象不被使用时会立即被回收。而 GC 的内存回收是一阵一阵的,回收时需要暂停程序,会有一定的卡顿。
ARC 相对于 GC 的缺点:
GC 真的是太简单了,基本上完全不用处理内存管理问题,而 ARC 还是需要处理类似循环引用这种内存管理问题。
GC 一类的语言相对来说学习起来更简单。
在 Wikipedia 上,还有更详细的优缺点对比,感兴趣的同学可以深入学习。
李洪强iOS经典面试题37-解释垃圾回收的原理的更多相关文章
- 李洪强iOS经典面试题31-解释垃圾回收的原理
李洪强iOS经典面试题31-解释垃圾回收的原理 问题 我们知道,Android 手机通常使用 Java 来开发,而 Java 是使用垃圾回收这种内存管理方式. 那么,ARC 和垃圾回收对比,有什么优点 ...
- 李洪强iOS经典面试题下
李洪强iOS经典面试题下 21. 下面的代码输出什么? @implementation Son : Father - (id)init { self = [super init]; if (self) ...
- 李洪强iOS经典面试题156 - Runtime详解(面试必备)
李洪强iOS经典面试题156 - Runtime详解(面试必备) 一.runtime简介 RunTime简称运行时.OC就是运行时机制,也就是在运行时候的一些机制,其中最主要的是消息机制. 对于C ...
- 李洪强iOS经典面试题155 - const,static,extern详解(面试必备)
李洪强iOS经典面试题155 - const,static,extern详解(面试必备) 一.const与宏的区别(面试题): const简介:之前常用的字符串常量,一般是抽成宏,但是苹果不推荐我们抽 ...
- 李洪强iOS经典面试题154- 通知与推送
李洪强iOS经典面试题154- 通知与推送 通知与推送 本地通知和远程推送通知对基本概念和用法? image 本地通知和远程推送通知都可以向不在前台运行的应用发送消息,这种消息既可能是即将发生的事 ...
- 李洪强iOS经典面试题153- 补充
李洪强iOS经典面试题153- 补充 补充 有空就来解决几个问题,已经懒癌晚期没救了... UML 统一建模语言(UML,UnifiedModelingLanguage)是面向对象软件的标准化建模 ...
- 李洪强iOS经典面试题147-WebView与JS交互
李洪强iOS经典面试题147-WebView与JS交互 WebView与JS交互 iOS中调用HTML 1. 加载网页 NSURL *url = [[NSBundle mainBundle] UR ...
- 李洪强iOS经典面试题144-数据存储
李洪强iOS经典面试题144-数据存储 数据存储 sqlite中插入特殊字符的方法和接收到处理方法. 除'其他的都是在特殊字符前面加"/",而 ' -> '' .方法:k ...
- 李洪强iOS经典面试题143-绘图与动画
李洪强iOS经典面试题143-绘图与动画 绘图与动画 CAAnimation的层级结构 CAPropertyAnimation是CAAnimation的子类,也是个抽象类,要想创建动画对象,应该使 ...
随机推荐
- PHP curl 抓取AJAX异步内容
其实抓ajax异步内容的页面和抓普通的页面区别不大.ajax只不过是做了一次异步的http请求,只要使用firebug类似的工具,找到请求的后端服务url和传值的参数,然后对该url传递参数进行抓取即 ...
- C# 解决无法识别的属性 configProtectionProvider
在使用.Net自身提供的加密本配置文件后再用System.Configuration.ConfigurationManager.AppSettings["key"]获取值时会出现“ ...
- sar详解(linux/unix通用)
转载:http://www.toxingwang.com/linux-unix/2027.html sar是linux和unix通用的性能报告工具,常用命令组合如下: sar 命令行的常用格式: sa ...
- DoxygenToolkit.vim
DoxygenToolkit.vim 常用命令: 光标在函数上,用 :Dox 自动生成函数的说明. 光标在文件头,用 :DoxAthor 自动生成文件说明. 下载地址
- vscode - 移动端适配(cssrem)
建议使用Chrome浏览器. 1.第一步,安装扩展以及配置 2.第二步,使用(记得按一下↓)
- PHP 正则表达式(PCRE)
PHP 正则表达式(PCRE) 正则表达式(regular expression)描述了一种字符串匹配的模式,可以用来检查一个串是否含有某种子串.将匹配的子串做替换或者从某个串中取出符合某个条件的子串 ...
- JUnit 3.8 让所有测试程序 实现 复合的测试(TestSuite)
之前是单个单个程序测试,这种方式在测试类比较少的时候可行, 但测试类多了,单个单个的这个测试方式就不推荐了,那得使用 复合的测试了 一个TestSuite是一个复合的测试.它运行测试用例集. 这个 ...
- C# Dictionary通过value获取对应的key值[转发]
1:最直白的循环遍历方法,可以分为遍历key--value键值对以及所有的key两种表现形式 2:用Linq的方式去查询(当然了这里要添加对应的命名空间 using System.Linq) 如下为一 ...
- Docker实战(五)编写Dockerfile
一.创建Dockerfile文件 首先,需要创建一个目录来存放 Dockerfile 文件,目录名称可以任意,在目录里创建Dockerfile文件: 二.Dockerfile 基本框架 Dockerf ...
- Solr 搜索功能使用
http://wiki.apache.org/solr/SolrQuerySyntax http://www.solrcn.com/index.php?s=查询