lufei's Studio.

内存管理

字数统计: 1.9k阅读时长: 6 min
2019/06/03 Share

看了andriod和iOS上不同的内存管理机制,写篇文章记录并总结一下,嘻嘻嘻。

iOS的内存管理

在日常iOS开发中,监控崩溃是一个很常见的事,但是总有一些崩溃是那么的无厘头,让人摸不着头绪,这种OOM有可能来自iOS的JetSam机制导致的一种“另类”崩溃,我们的日志系统是无法通过信号捕捉到的。

JetSam 机制,指的就是操作系统为了控制内存资源过度使用而采用的一种资源管控机制

不同的系统版本对App运行时占用内存的限制不同,有一种方法就是查看手机中以 JetsamEvent开头的系统日志(设置 -> 隐私 -> 分析)。

系统版本的升级也会增加占用的内存,App功能的增多也会要求越来越多的内存

因为移动设备的内存资源有限,当App运行时占用的内存大小超过了限制后,就会被强制杀掉,这也是作为开发者需要重视内存管理的原因。

苹果公司主要采用的内存管理技术是引用计数方法

引用技术可以及时地回收引用计数为0的对象,减少查找次数,但是引用计数会带来循环引用的问题,我们需要通过弱引用,来解决问题。

另外,在ARC之前,一直是通过MRC这种手写大量内存管理代码的方式来管理内存的,相当麻烦,后来苹果公司开发了ARC技术,由编译器来完成这部分代码,不过依然需要注意循环引用的问题,而且运行时错误往往难以定位,所以写的时候遇到可能导致循环引用的地方,需要多多考虑一下。

当ARC的内存管理代码交由编译器自动添加之后,某些情况下效率比MRC低一些,所以,在性能敏感的模块,也可以考虑MRC。

andriod内存管理

andriod主要有GC(Garbage Collection)的标记清除算法,这种技术可以自动清空中不再使用的对象。

在Java中,对象是通过引用使用的,如果没有引用指向该对象,该对象就无法处理和被调用,类似这样的对象称为不可到达(unreachable),垃圾回收用于释放不可到达的对象所占据的内存

主要的实现思想:遍历栈中所有的对象的引用,再遍历一遍堆中的对象。因为栈中的对象的引用执行完毕就删除,所以我们就可以通过栈中的对象的引用,查找到堆中没有被指向的对象,对这些对象其进行垃圾回收。(标记回收算法(Mark and Sweep GC)

其他还有复制算法(Copying), 标记-压缩算法 (Mark-Compact), 分代

如果持有对象的强引用,垃圾回收器是无法在内存中回收这个对象

当然这种机制也是有一些小问题的,比如这个过程需要中断进程中的其他组件,并且可能产生内存碎片,也就是大量的不连续的内存。

当然似乎这些问题在ART上被解决的还不错~

虚拟内存

要想深入了解管理内存的方式,我们不仅仅要关注用户态接口层面,比如引用计数算法和循环引用监控技巧,还需要了解管理内存的演进过程。

在最开始的时候,程序员直接访问物理内存,但是到了多程序多任务同时运行,就出现了很多问题,比如同时运行的总内存必须要小于实际物理内存大小,程序能够直接访问物理内存,也就能直接访问和修改其他程序的数据,运行时的安全也就无法保障,于是虚拟内存(VM)就应运而生。

由于要解决以上问题,聪明的前辈们想到了办法,增加了一个中间层,称为虚拟内存,然后虚拟内存通过映射,再将虚拟地址转化为物理地址

虚拟内存是硬件异常,硬件地址翻译,主存,磁盘文件和内核软件的完美交互,它为每个进程提供了一个大的,一致的和私有的地址空间。

虚拟内存的能力:

  • 它将主存看成是一个存储在磁盘上的地址空间的高速缓存,在主存中只保存活动区域,并根据需要在磁盘和主存之间来回传递数据,通过这种方式,高校地使用了主存。
  • 它为每个进程提供了一致的地址空间,简化了内存管理。
  • 它保护了每个进程的地址空间不被其他程序破坏。

因为VM会给每个程序创建一个单独的执行环境,也就是一个独立的虚拟空间,这样每个程序就只能访问子集的地址空间(Address Space),程序与程序间也就被安全地隔离开了。并且操作起来和物理内存一样高效。

概念上来说,虚拟内存被组织为一个由存放在磁盘上的N个连续的字节大小的单元组成的数组。每字节都有一个唯一的虚拟地址,作为到数组的索引。磁盘上数组的内容被缓存在主存中。和存储器层次结构中其他缓存一样,磁盘上的数据被分割为块,这些块作为磁盘和主存之间的传输单元。VM系统通过将虚拟内存分割为称为虚拟页(Virtual Page, VP)的大小固定的块来处理这个问题。类似地,物理内存被分割为物理页(Physical Page, PP), 也被称为页帧(page frame)。

在任意时刻,虚拟页面的集合都分为三个不相交的子集:

  • 未分配的
  • 缓存的
  • 未缓存的

SRAM缓存表示位于CPU和主存之间的L1,L2和L3高速缓存,用DRAM缓存来表示虚拟内存系统的缓存,它在主存中缓存虚拟页
这样操作系统只需要维护一份页表(Page Table)来记录虚拟页和物理页的关系就好了,不需要考虑堆和栈具体会申请多少空间,只需要考虑多少页就好了

虚拟页的前两位是Virtual Page Number, 根据页表,翻译为物理地址Physical Frame Number

虚拟页和物理页之间的映射关系,也就是虚拟内存和物理内存的关系,如下图所示:

虚拟内存和物理内存关系

翻译步骤:

  • 处理器生成一个虚拟地址,并把它传送给MMU。
  • MMU生成PTE地址,并从高速缓存或主存中请求得到
  • 高速缓存或主存向MMU返回PTE
  • MMU构造物理地址,并把它传送给高速缓存或主存
  • 高速缓存或主存返回所请求的数据字给处理器

当然虚拟内存的内容很多,简单一篇文章也说不明白,还需要多多去查看资料,去理解~

CATALOG
  1. 1. iOS的内存管理
  2. 2. andriod内存管理
  3. 3. 虚拟内存