http://www.cocoachina.com/ios/20150625/12234.html

说起内存管理,看似老生常谈,而真正掌握内存管理的核心其实并不简单。ARC/MRR以及“谁分配谁就负责释放”这种基本原则是很重要的,但不是本文要讨论的重点。之前本人还没在小站发过相关的文章,本篇文章中,我本人是想结合实际开发和调试中遇到的一些细节问题,来谈谈iOS的内存管理内在机制和调试方法。

上一篇文章已经是4月份的了,时间飞快又过去了好久,小站5月份没有文章更新,罪过罪过。最近小站的站长我又转换到新团队新岗位,在支付宝做客户端开发感受颇多,不过身在一个技术流团队,工作很有挑战,自己感觉很充实、很“幸福”。iOS开发当中的内存管理,可深可浅,一般应用程序开发过程当中可能并不需要关注太多,如果不是来到支付宝,也许就不会有这么多心得来整理此文。

关于内存,我准备分为内存管理的基本原则、原理和调试方法、实际问题几部分整理。那么接下来我就和大家一起复习和稍微深入一下iOS的内存管理的原理和原则。

0. 概述

内存,简单来说就是内部存储,复杂来说要从冯·诺依曼计算机结构说起。冯·诺依曼结构,也称做普林斯顿结构,目前和哈佛结构相对,指出了计算机由运算器、控制器、存储器、输入和输出设备几大部件组成。如今我们个人用的机器估计都是这个套路,而且运算器和控制器都合在一起,就是CPU,中央处理器。那么内存就是CPU能直接读写访问数据的地方(寄存器是在CPU内的,不算哈),有些朋友说谁谁谁的iPhone内存16G、64G,我只能说这个理解方法仅限于存储部件放在手机里(内)了,严格来讲这算“外存”,我们要讨论的不是这个。

冯·诺依曼结构还说了,内存是用来存啥的呢?指令+数据!(哈佛的恐怕就不一样了)对于我们开发者来说,指令基本就是代码逻辑,至于数据么变量常量肯定都算是的了。

内存有多大?不大,现今主流的个人机器也就几G的样子。iPhone?  统统1G。

我们操作系统都是运行在内存之上的,1G好像不算大,所以为了支持多进程,也为了支持大程序,抽象的虚拟存储的概念诞生了。

简要的概念先陈述到这,下面详细说。哦,对了,ARC和MRR我还是得提一下,这个要是真不知道还真的自己先去了解一下去。

1. 通用内存基本原理

说iOS的内存,有必要先看看一般的计算机都是怎么干的,iPhone也是计算机,通用的道理一样要遵循。这里提两方面:虚存的概念,内存内容的大致分布。

虚拟存储系统。刚刚提到了,物理内存就那么大点,但是还要跑多个程序,还要接受消耗很大内存的程序,这怎么办?凉拌。搞计算机的人都是很聪明的,在操作系统层面做了物理地址和逻辑地址之间的映射转换,当然处理器硬件上也做了支持。一个程序在运行时,实际要用到的指令和数据都是很有限的,不可能从头到尾同时用。那么对于一个程序来说,假装自己有非常大的空间,实际上只要有条理的把暂时要用到的部分放进物理内存供CPU访问就好,这样第二个问题解决了。那既然每个程序(进程)只用一小块,那整个物理内存就可以分给多个程序(进程)用了,第一个问题也迎刃而解。当然,这样做的前提是,数据和指令的动态进出,用完了的暂时不用的踢出内存,需要用的及时加载进来。这个具体的实现方式就多种多样了,很多实现方式是在外存中开了个交换区供换入换出,但iOS可略有不同。

内存的大致分布。不久以前,我发了一篇文章整理了Mach-O文件的格式分析,里面很复杂地放了好多东西,包括我们Build打包时的代码和数据。而Mach-O文件正是我们开发内容的一个静态展现形式,要想在运行的时候看样子,就得看这文件里包含的东西是怎么放进内存的。Objective-C是基于C的,不放看下C程序进程的内存分布:

一个运行时进程的典型内存分布

最简单来说分为两大部分:指令+数据。再细分一点,五部分:代码(指令),初始化数据区,未初始化数据区,堆,栈。

  • 代码(指令,text)就不用说了,最静态的,就是只读的东西;

  • 初始化数据,简单理解就是有初始值的变量、常量;

  • 未初始化数据,只声明未给值的变量,运行前统统为0,之所以单独分出来,估计是性能考虑,因为这些东西都是0,没必要放在程序包里,也不用copy;

  • 栈,程序运行记录,每个线程,也就是每个执行序列各有一个(看crash log最容易理解),都是编译的时候能确定好的,还有一个特点就是这里面的数据可以不用指针,也不会丢;

  • 堆,最灵活的内存区,用途多多,动态分配和释放,编译时不能提前确定,我们的Objective-C对象都是这么来的,都存在这里,通常堆中的对象都是以指针来访问的,指针从线程栈中来,但不独属于某个线程,堆也是对复杂的运行时处理的基础支持,还有就是ARC还是MRR、“谁分配谁释放”说的都是堆上对象的管理;

其实,这个内存中的布局方式大部分操作系统中的大部分进程都是类似的。Objective-C的程序包对运行时有着复杂的支持和内容划分,但也都是在这个大的框架下进行的。

2. iOS的内存管理

其实,iOS的内存管理和其它操作系统大同小异。这里按照苹果文档所述,重点对堆内存分配整理下。

首先,iOS和其它系统一样,内存分页,每页4K。多个页构成一个region统一管理,负责管理的对象是VM object,其中包含了pager、size、resident pages等诸多属性。

不管是Objective-C的[NSObject alloc],还是C代码的对内存分配,最终重任都会落到malloc库上,释放也是如此,最终都将使用malloc库中的free()。

malloc库中有很多malloc的同族函数可以动态分配内存,会结合参数在free pages中进行最适分配。如果分配的内存比较大,可以直接使用vm_allocate,得到一个VM对象(与Linux类似),这个在实际使用前不分配物理内存。malloc的内部实现都是开源的,感兴趣的可以去了解去看。

此外,对于malloc,还有一个Zone的概念(貌似与Linux的概念不完全相同),可以简单理解为一组free page单元,可以统一管理操作。默认情况,在第一次调用malloc时,系统会生成一个default zone,后续的默认分配在此进行。比如,malloc_zone_xxx()函数都是对特定的zone进行分配操作,执行zone->xxx()。

最后强调一下iOS特别需要注意的点:

当前的主流iPhone实际物理内存都不超过1G,可以说不算大。不过和Android机比起来,我不得不为苹果的设计称赞,1G空间利用得如此高效,性能不差,也控制了发热。

那么在这仅有的1G内存中,iOS的操作系统更是抛弃了不必要的复杂——系统层面不支持App内存页换出。当内存吃紧时,对于可以重新载入的只读数据来说,直接清理掉,而对于可写的数据,只能通过App自己去管理维护。内存紧张时,iOS会向App发起memory warning,不配合释放足够内存者,杀!

App调试时的物理内存情况

上图是使用Activity Monitor调试时的一个截图,可以看到在尽量不释放自身内存的情况下(为了bug调试特意这么做的),支付宝钱包的内存可以做到502M物理内存占用。再稍微高一点点,系统就会连前台运行的App一起Kill掉。留下一个Unknown的log。

3. 其它

基本的原理就简要整理到此,如下是一些参考:

说说iOS与内存管理(上)的更多相关文章

  1. 理解 iOS 的内存管理

    远古时代的故事 那些经历过手工管理内存(MRC)时代的人们,一定对 iOS 开发中的内存管理记忆犹新.那个时候大约是 2010 年,国内 iOS 开发刚刚兴起,tinyfool 大叔的大名已经如雷贯耳 ...

  2. iOS ARC内存管理

    iOS的内存管理机制,只要是iOS开发者,不管多长的时间经验,都能说出来一点,但是要深入的理解.还是不简单的.随着ARC(自动管理内存)的流行.iOS开发者告别了手动管理内存的复杂工作.但是自动管理内 ...

  3. iOS之内存管理(ARC)

    iOS的内存管理,相信大家都不陌生,之前是使用的MRC,由开发人员手动来管理内存,后来使用了ARC,来由系统管理内存.本文主要讲讲Autorelease,Core Foundation对象在内存管理方 ...

  4. iOS的内存管理和引用计数规则、Block的用法以及三种形式(stack、malloc、global)

    学习内容 iOS的内存管理和引用计数规则 内存管理的思考方式 自己生成的对象自己持有 非自己生成的对象自己也能持有 自己持有的对象不需要时释放 非自己持有的对象不能释放 ARC有效时,id类型和对象类 ...

  5. 垃圾回收GC:.Net自己主动内存管理 上(一)内存分配

    垃圾回收GC:.Net自己主动内存管理 上(一)内存分配 垃圾回收GC:.Net自己主动内存管理 上(一)内存分配 垃圾回收GC:.Net自己主动内存管理 上(二)内存算法 垃圾回收GC:.Net自己 ...

  6. C语言堆内存管理上出现的问题,内存泄露,野指针使用,非法释放指针

    C语言堆内存管理上出现的问题,内存泄露,野指针使用,非法释放指针 (1)开辟的内存没有释放,造成内存泄露 (2)野指针被使用或释放 (3)非法释放指针 (1)开辟的内存没有释放.造成内存泄露,以下的样 ...

  7. 垃圾回收GC:.Net自己主动内存管理 上(二)内存算法

    垃圾回收GC:.Net自己主动内存管理 上(二)内存算法 垃圾回收GC:.Net自己主动内存管理 上(一)内存分配 垃圾回收GC:.Net自己主动内存管理 上(二)内存算法 垃圾回收GC:.Net自己 ...

  8. 垃圾回收GC:.Net自己主动内存管理 上(三)终结器

    垃圾回收GC:.Net自己主动内存管理 上(三)终结器 垃圾回收GC:.Net自己主动内存管理 上(一)内存分配 垃圾回收GC:.Net自己主动内存管理 上(二)内存算法 垃圾回收GC:.Net自己主 ...

  9. iOS - OC 内存管理

    1.OC 基本内存管理模型 1.1 自动垃圾收集 在 OC 2.0 中,有一种称为垃圾收集的内存管理形式.通过垃圾收集,系统能够自动监测对象是否拥有其他的对象,当程序执行需要空间的时候,不再被引用的对 ...

随机推荐

  1. FileReader详解

    一.兼容性 从上图中可以看出IE7.8.9都不支持FileReader对象 二.作用 使用支持FileReader浏览器的用户可以通过一个file input选择一个图像文件将图片显示在页面中,而不用 ...

  2. Css 进阶学习

    以下样式,表示css对第一个li标签无效,第一个以后的样式有效. .nav-pills>li+li { margin-left: 2px } <ul class="nav-pil ...

  3. 20190813-Sunburst

    Sunburst-7obu&Itro 雨过天晴. 考试过程 刚开始挺郁闷的,上一个T2还在改(50/50/51)XD 先通看三题. T1好像是树?? T2可以把环拆成链. T3好像是BFS?? ...

  4. navicat修改mysql用户密码,前提是能登陆

    幸亏之前已经连上了数据库后边才忘记密码

  5. CentOS7配置中文支持与部署GitLab服务器

    给你的 CentOS 7 安装中文支持 1.首先需要中文字体以便支持命令行终端的中文显示需求: yum groupinstall "fonts" 碰到提示输入 y 回车继续安装,大 ...

  6. hadoop-hive查询ncdc天气数据实例

    使用hive查询ncdc天气数据 在hive中将ncdc天气数据导入,然后执行查询shell,可以让hive自动生成mapredjob,快速去的想要的数据结果. 1. 在hive中创建ncdc表,这个 ...

  7. linux系统RabbitMQ启动错误记录

    安装并配置好RabbitMq之后终端执行rabbitmq-server报错 试了网上的各种方法也无济于事 最后发现可能是因为访问权限的问题(并不确定) 解决方法:sudo rabbitmq-serve ...

  8. webpack学习之—— Code Spliting(代码分离)

    代码分离特性能够把代码分离到不同的 bundle 中,然后可以按需加载或并行加载这些文件.代码分离可以用于获取更小的 bundle,以及控制资源加载优先级,如果使用合理,会极大影响加载时间. 有三种常 ...

  9. GCC/GDB学习

    GCC学习 1.gcc是根据后缀名来区分文件的 .c : c语言源文件 .a : 目标文件构成的库文件 .C/.cc/.cxx : c++源文件 .h : 头文件 .i : 预处理过的C源文件 .ii ...

  10. JS---案例:图片跟着鼠标飞的最终版本

    案例:图片跟着鼠标飞的最终版本 换了个好看的糖果照片,想给博客首页加上,但是加上后,应该是overwrite原来的html,所以光有鼠标跟着飞的效果,原来的功能都不能用了 放入common.js &l ...