简介
存储器层次结构
操作体系内存对应物理存储结构中为L4主存,因为操作体系中指令集和虚拟内存2大笼统,关于操作体系而言虚拟内存是对应的操作办理的空间,虚拟内存经过MMU与物理内存作映射。
虚拟内存
经过MMU完成的虚拟寻址,供给虚拟的地址空间。关于每个进程来说,操作体系供给了一个独立私有且接连的地址空间
完成
虚拟寻址
- 物理寻址
计算机体系的主存被组织成一个由M个接连的字节巨细和单元组成的数组。每字节都有一个仅有的物理地址。第一个字节地址是0,第二个地址是1,再往下是2,依此类推
- 虚拟寻址
CPU经过生成一个虚拟地址来拜访主存,这个虚拟地址在被送到内存之前被转换成适当的物理地址。CPU芯片上有叫做内存办理单元(Memory Management Unit, MMU)的专用硬件,运用存放在主存中的查询表来动态翻译虚拟地址
- 地址空间
地址空间是一个非负整数地址的有序调集
分页
和存储器层次结构中其他缓存相同,磁盘(较低层)上的数据被切割成块,这些块作为磁盘和主存(较高层)之间的传输单元。VM体系经过将虚拟内存切割成称为虚拟页(Virtual Page,VP)的巨细固定的块来处理这个问题。类似地,物理内存被切割为物理页(Physical Page,PP),巨细也为P字节(物理页也被称为页帧(Page Frame))
恣意时刻,虚拟页面的调集都分为
- 未分配的
VM体系还未分配或创立的页
- 缓存的
当时已缓存在物理内存中的已分配的页
- 未缓存的
未缓存在物理内存中的已分配的页面
效果
- 作为缓存的东西
- 作为内存办理的东西
- 作为内存保护的东西
缓存
从存储器层次结构来看,DRAM比SRAM要慢50倍,SSD固态硬盘比DRAM要慢1000倍
页表
跟任何缓存相同,虚拟内存体系必须有某种办法判定一个虚拟页是否在内存中。假如在内存中,是在哪个物理页。假如不在内存中,是在磁盘哪个位置,并在物理内存中挑选一个献身页,并将虚拟页从磁盘仿制到内存中。
这些功用由操作体系,MMU中的地址翻译硬件和一个存放在物理内存中的数据结构,即页表(page table),页表将虚拟页映射到物理页。每次地址翻译硬件将一个虚拟地址转换为物理地址时,都会读取页表。
页射中
页射中的状态下,地址翻译硬件将虚拟地址作为一个索引来定位物理地址,直接从物理地址读取。
缺页
内存缓存不射中称为缺页。地址翻译硬件从内存中读取,从有效位判断未缓存,触发缺页反常。缺页反常调用内核中的缺页反常处理程序,挑选献身页,仿制虚拟页从磁盘到献身页。
当反常处理程序返回时,会从头启动导致缺页的指令,该指令会把导致缺页的虚拟地址从头发送到地址翻译硬件,走页射中相同的逻辑。
这边的缺页导致了需求挑选内存献身页和从磁盘仿制,导致了一次剩余的IO,因为磁盘的读取速度比DRAM低得多,所以缺页会影响内存读取功能。
抖动
因为局部性原理,虽然缺页的本钱比较高,可是缺页的触发一般不会频繁。虽然整个运转进程中程序引证的不同页面总数可能超过物理内存总的巨细,可是局部性原理保证了在恣意时刻,程序将趋向于在一个较小的活动页面(active page)调集上作业,这个调集叫做作业集(working set)或许常驻调集(resident set)。
可是假如作业集的巨细超出了物理内存的巨细,那么程序会产生一个不良的状态,抖动(thrashing),页面将不断换进换出,导致功能低下。
内存办理
操作体系为每个进程供给了一个独立的页表,一个独立的虚拟地址空间。按需页面调度和独立的虚拟地址空间的结合,对体系中内存的运用和办理造成了深远影响。尤其是VM简化了链接和加载,代码和数据同享,以及应用程序的内存分配。
- 简化链接
独立的地址空间允许每个进程的内存映像运用相同的根本格式,而不管代码和数据实际存放在物理内存的位置
- 简化加载
虚拟内存还使得简略向内存中加载可执行文件和同享目标文件
- 简化同享
独立地址空间为操作体系供给了一个办理用户进程和操作体系自身之间同享的共同机制
- 简化内存分配
虚拟内存为向用户进程供给一个简略的分配额外内存的机制
内存保护
供给独立的地址空间使得区分不同进程的私有内存变得简略,地址翻译机制能够以一种自然的办法扩展到供给更好的拜访操控
假如一条指令违反了答应条件,CPU就触发一个一般保护故障,将操控传递给内核中反常处理程序。Linux Shell一般将这种反常称为“段错误(Segmentation fault)”
Linux虚拟内存体系
Linux为每个进程保护了一个独自的虚拟地址空间
iOS内存机制
Memory in Use = memoryPage * pageSize
iOS中内存页类型
-
clean memory
- 能够被移出内存的数据
- 内存映射文件
- Frameworks一部分,如__DATA_CONST段
-
dirty memory
- app修改的内存
- 一切堆内存分配
- 解码后的图片缓存区
- Frameworks中__DATA_DIRTY部分
-
compressed memory
- 没有传统内存交流
- 压缩用不到的内存页
- 当需求运用的时分解压
Virtual memory = clean memory + dirty memory
phys_footprint = dirty memory + compressed memory
Footprint约束
- 不同设备不同
- App一般有较高的footprint内存约束
- Extensions有比较低的内存约束
内存超出约束的反常类型
- EXC_RESOURCE_EXCEPTION
Resident memory = dirty memory + clean memory loaded in phisical
内存办理办法
- Purgeable Memory
Cocoa框架也供给了NSPurgeableData类来协助保证不会运用过多内存,NSPurgeableData类遵从NSDiscardableContent协议,这个协议的效果是假如拜访这个类的实例的目标结束了拜访能够开释这个类的实例的内存。你在创立具有一次性质组件的目标时,需求完成NSDiscardableContent。别的NSPurgeableData类运用时跟NSCache没有关联,你能够独立运用
- Memory Compression
操作体系在PC端一般会有内存交流机制,可是移动端受限于电量和闪存本钱,iOS中对应与内存交流的是一种内存压缩机制
- APP nap
假如一个app没有正执行例如更新屏幕内容等用户初始化的作业,播映音乐或许下载文件,体系能够把APP放到APP Nap中。APP Nap经过调理应用程序的CPU运用率和降低计时器的触发频率来节省电池寿命。
- Memory pressure warnings
在iOS体系中有几种不同等级的memory pressure warning,从“normal”到“critical”,包含Jetsam机制
- Low memory notifications
UIKit运用了几种办法来接纳地内存通知
- 在application delegate里完成applicationDidReceiveMemoryWarning:办法
- 在你自定义UIViewController的子类里重写didReceiveMemoryWarning办法
- 注册UIApplicationDidReceiveMemoryWarningNotification对应的通知
内存办理
内存映射
经过将一个虚拟内存区域与一个磁盘上的目标(object)关联起来,以初始化这个虚拟内存区域的内容,这个进程称为内存映射(memory mapping)
除了体系运用内存映射同享一些目标和区域外,也供给了用户级的mmap函数来创立新的虚拟内存区域,并将目标映射到这些区域
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
动态内存分配
动态内存分配器保护着一个进程的虚拟内存区域,称为堆(heap)。分配器将堆视为一组不同巨细的块(block)的调集来保护。每个块就是一个接连的虚拟内存片(chunk),要么是已分配的,要么是闲暇的。
c标准库供给了一个称为malloc程序包的分配器。
#include <stdlib.h>
void *malloc(size_t size);
废物搜集
废物搜集器将内存视为一张有向可达图(reachability graph),该图的节点被分成一组根节点(root node)和一组堆节点(heap node)。
当存在一条从恣意根节点动身并到达某节点的有向路径时,我们说该节点是可达的。在任何时刻,不可达节点是废物,不能被再次运用。废物搜集器的角色是保护可达图的某种表明,并经过开释不可达节点且将它们返回给闲暇链表。
像ML和Java这样的言语的废物搜集器,对应用如何创立和运用指针有很严格的操控,能够保护可达图的一种精确的表明,因此能够回收一切废物。
C++这样的言语的搜集器一般不能保持可达图的精确表明,这样的搜集器也叫做保存的废物搜集器(conservative garbage collector)
iOS中是运用主动引证计数(Automatic Reference Counting)来清理废物。
GC
Java
ARC
每次当你创立一个类的实例的时分,ARC分配一个片的内存用于存储对应实例的信息。这片区域存储了实例的类型和跟实例关联的属性。
别的当一个实例不再需求的时分,ARC开释被实例运用的内存,之后内存能够用作其他用处。这保证了实例不被用到的时分不会占用内存空间。
循环引证
假如有2个目标相互对目标持有强引证,这样2个目标都能够保持存活,这被称作循环引证。
内存泄漏
内存泄露包含了OC和Swift言语层面的循环引证,也包含了C,C++等言语和库创立目标后未开释等原因。
内存泄露检测东西
iOS中常见的内存泄露检测东西如下
-
MLeaksFinder
-
FBRetainedCycle
- NSObject
- Block
- Timer
- Associated Objec
引证
《深入理解计算机体系》
iOS Memory Deep Dive
Memory Usage Performance Guidelines
Improving Your App’s Performance