精华内容
下载资源
问答
  • 内存管理基本思想与算法

    千次阅读 2018-05-30 16:46:59
    介绍操作系统是如何来管理内存资源。 层次化存储体结构 计算机的存储体系 寄存器(register) 在CPU内部,非常快速,昂贵 高速缓存(cache) 非常快速,昂贵,容量小,易失性 主存(RAM) 中等速度,...

    介绍操作系统是如何来管理内存资源。

    层次化存储体结构

    计算机的存储体系

    • 寄存器(register)
      • 在CPU内部,非常快速,昂贵
    • 高速缓存(cache)
      • 非常快速,昂贵,容量小,易失性
    • 主存(RAM)
      • 中等速度,中等价格,易失性
    • 外存
      • 容量大,速度慢,种类多,不易失

    操作系统的工作就是协调这些存储器的使用,管理存储器的部分程序被称为存储管理器

    • 记录存储使用状况
    • 分配、回收存储资源
    • 数据的装入与写回

    存储管理系统分类

    在运行期间,进程需要在内存和磁盘之间换进换出的系统(交换和分页)和不需要换进换出的系统

    不需要换进换出的系统

    • 特点:进程被调入运行后,它将始终位于内存中,直至运行结束
    • 没有交换和分页的单道程序
    • 固定分区的多道程序

    不需要换进换出的系统实现起来是最简单的,但无法做到并发等现代操作系统的高级功能。

    基本的存储管理

    单道程序存储管理

    • 同一时刻只运行一道程序应用程序和操作系统共享存储器

    • 相应地,同一时刻只能有一个进程在存储器中运行。

    • 一旦用户输入了一个命令,操作系统就把需要的程序从磁盘贝到存储器中并执行它;在进程运行结束后,操作系统显示出个提示符并等待新的命令。当收到新的命令时它把新的程序装入存储器,覆盖掉原来的程序

    实现方案

    将操作系统和应用程序在RAM上存放位置的不同分为以下三种结构:

    52764925885

    固定分区的多道程序系统

    将内存划分为n个分区(可能不相等),分区的划分可以在系统启动时手工完成。

    实现方案

    1. 每个分区分别有一个运行队列

      • 当一个作业到达时,可以把它放到能够容纳它的最小的分区的输入队列中
      • 这会造成小分区的队列是满的,而大分区的输入队列却是空的
    2. 各分区共享同一个输入队列

      如果选择小进程先运行,则会浪费内存空间;而如果选择大进程运行,则对小进程不利。

      • 一种算法是至少保留一个小分区,这样小进程就可以直接运行不与大进程竞争
      • 另一种方式是制定一条规则:规定一个进程被忽略的次数不能超过k次

    重定位和存储保护

    多道程序引发了两个很重要的问题:

    1. 当一个程序被链接时,必须知道程序将在内存的什么地方运行
    2. 当一个程序运行时,它只能访问自己的内存空间

    重定位

    使用相对地址进行链接。

    当一个程序被装入内存时,直接对指令代码进行修改,一次性实现文件内的相对地址到内存中绝对地址之间的转换(一般为线性)

    在装入时重定位并没有解决保护问题,一个恶意的程序总可以生成一条新指令去访问任何它想访问的地址

    地址保护

    1. 每个内存块分配4位的保护码,PSW中包含一个4位的密钥,若运行进程试图对保护码不同于PSW中密钥的主存进行访问,则由硬件引起一个陷入

    2. 另一种解决方式是在机器中增加两个特殊的硬件寄存器,基地址(base)和边界(limit)寄存器

      程序分区的起始地址存储在基地址寄存器中

      分区的长度存储在边界寄存器中

      当访问内存单元时,直接用基地址加上指令地址访问

      缺点是每一次内存访问都增加了一次加法和比较操作。

    交换技术(swapping)

    随着程序越来越大,我们已经无法一次性把程序全部放到内存同时运行,因此产生了两种技术:交换技术(swapping)和虚拟存储器(virtual memory)

    原理

    把各个进程完整地调入主存,运行一段时间,再放回到磁盘上,过段时间再调入运行。

    可采用固定分区和可变分区。

    内存紧缩(memory compaction)

    当交换在主存中生成了多个空洞时,可以把所有的进程向下移动至相互靠紧,从而把这些空洞结合成一大块。

    但这样会造成CPU资源浪费。

    使用可变内存策略来减少进程移动或换入换出的次数。

    支持可变内存策略

    如果预计大多数进程在运行时都要增长,那么可以在进程被换入或移动时分配多一点的内存,从而减小系统开销。

    但如果进程需要换出磁盘,只需要交换进程实际占用的内存内容。

    实现方案

    基于位图的存储管理

    内存被划分为可能小到几个字或大到几千字节的分配单位,每个分配单位对应于位图中的一位,0表示空闲,1表示占用(或者反过来)。

    52766558313

    位图的大小仅仅取决于内存分配单位的大小。

    缺点:在位图中查找指定长度的连续0串是一个缓慢的操作。

    基于链表的存储管理

    跟踪内存使用的另一个方法是维持一个已分配和空闲的内存段的链表

    链表中的每一个表项都包含下列内容:

    • 指明是空洞(H)还是进程(P)的标志
    • 开始地址、长度
    • 指向下一个表项的指针。

    内存分配算法

    首次适配算法(first fit)

    • 存储管理器沿着内存段链表搜索直到找到一个足够大的空洞

    下次适配(next fit)

    • 每次找到合适的空洞时都记住当时的位置,在下次寻找空洞时从上次结束的地方开始搜索,而不是每次都从头开始

    最佳适配算法(best fit)

    • 试图找出最接近实际需要的大小的空洞,而不是把一个以后可能会用到的大空洞先使用
    • 实际性能其实很差,因为会造成很多空洞

    • 每次被调用时都要搜索整个链表,因此会比首次适配算法慢

    最坏匹配算法(worst fit)

    • 在每次分配时,总是将最大的那个空闲区切去一部分,分配给请求者

    进程链表和空闲链表分离

    • 这样可以加快链表的查找速度
    • 但使得内存的回收变得更加复杂,速度更慢

    快速匹配算法(quick fit)

    • 为一些经常被用到长度的空洞设立单独的链表
    • 快速适配算法寻找一个指定大小的空洞是十分迅速的,但在一个进程结束或被换出时寻找它的邻接块以查看是否可以合并是非常费时间的

    虚拟存储管理

    基本思想

    • 操作系统把程序当前使用的那些部分保留在存储器中,而把其他部分保存在磁盘上。
    • 程序的代码、数据、栈可以超过实际可用的物理内存的大小

    分页技术(paging)

    虚地址空间被划分成称为页面(pages)的单位,在物理存储器对应的单位称为页框(page frames),页和页框总是同样大小的。

    由程序产生的地址被称为虚地址(virtual addresses),他们构成一个虚地址空间(virtual address space)

    • 在使用虚拟存储器的情况下,虚地址不是被直接送到内存总上,而是送到存储管理单元(MMU),它在CPU中,其功能是把虚地址映射为物理地址
    • 52766632264

    缺页故障(Page Fault)

    当访问未有映射的虚拟页,会引发陷入,这个陷入称为缺页故障。

    操作系统找到一个很少使用的页框并把它的内容写入磁盘,随后把需引用的页取到刚才释放的页框中,修改映射,然后重新启动引起陷入的指令。

    页表(Page Table)

    虚地址被分成虚页号(高位)偏移(低位)两部分,

    • 虚页号被用做页表的索引以找到该虚页对应的页表项,从页表项中可以找到页框号(如果有的话)。
    • 页框号被拼接到偏移的高位端,形成送往内存的物理地址。

    主要问题

    1. 页表可能会非常大
    2. 地址映射必须十分迅速

    多级页表

    使用多级页表来解决页表过大的问题。

    因为局部性原理,程序实际访问的地址空间是很小的一部分,因此可以多次映射来将不需要的页表存储在磁盘中。

    52766780259

    优点

    • 避免将进程的所有页表项一直保存在内存中

    缺点

    • 需要多次访问内存,以查找页表

    页表项的结构

    52766797005

    页框号

    • 物理页面号

    有效位

    • 这一位是1时这个表项是有效的可以被使用,如果是0,表示这个表项对应的虚页现在不在内存中,访问这一位为0的页会引起Page Fault

    保护位

    • 指出这个页允许什么样的访问。
    • 在最简单的形式下这个域只有一位,0表示读写,1表示只读。一个更先进的安排是使用三位,各位分别指出是否允许读、写、执行这个页。

    修改位和访问位跟踪页

    • 在一个页被写入时硬件自动设置修改位,如果一个页已经被修改过,则必须把它写回磁盘,否则只用简单地把它丢弃就可以了
    • 访问位在该页被引用时设置,被用来帮助操作系统在发生页面故障时选择淘汰的页,不再使用的页要比在使用的页更适合于被淘汰

    禁止缓存位

    • 这个特性对那些映射到设备寄存器而不是常规内存的页面是非常重要的。

    TLB

    由于访问页表(内存中)依然不够快,因此在CPU中有一小部分页表的拷贝,这部分页表是由最近访问页的页表项组成,称为TLB

    当一个虚地址被送到MMU翻译时,硬件首先把它和TLB中的所有条目同时(并行地)进行比较;如果找到了并且这个访问没有违反保护位,它的页框号将直接从TLB中取出而不用去查页表。

    反置页表

    物理存储器的每个页框对应一个页表项,而不是虚地址空间中的每个虚页对应一个页表项。

    优点:节省大量为保存页表所需要内存空间

    缺点:查找过程复杂

    页面替换算法

    动机

    当发生缺页中断时,需从磁盘上调入相应的页面,然而内存已满,需要选取内存中的页面,将其换出,并装入新页面。

    如何从众多的页面中选取被置换的页面?

    • 为此提出了各种算法
    • 可以应于缓存块的置换、Web缓冲区的更新等

    页面替换算法

    The Optimal Page Replacement Algorithm

    • 选择等待时间最长的那个页面被替换。
    • 无法实现,因为无法知道一个页面还要等待多久被访问。

    The Not Recently Used Page Replacement Algorithm

    • 统计访问位和修改位,在一个时钟周期内,选择未被访问也未被修改的页面被替换
    • 在一个时钟周期结束后,访问位会被清零

    FIFO Page Replacement Algorithm

    不是很好的算法,最先进入的页面也有可能是经常访问的页面

    The Second Chance Page Replacement Algorithm

    • 对FIFO的改进,如果访问位为1,那么曾经访问过,就把其清零,然后把页面放到链表的尾端,修改装入时间。
    • 如果访问位为0,则直接淘汰。
    • 实际上式寻找古老而且从上一次时钟中断以来未被访问的页面

    The Clock Page Replacement Algorithm

    • 改进二次机会算法,使用环形链表形式,避免了链表指针移动。

    Least Recently Used Algorithm

    • 将内存中最久未被访问的页面淘汰
    • 每次访问都会造成链表节点更新,开销较大。
    • 可以使用硬件支持来加速
    • 使用软件模拟(老化)
      • Not Frequently Used Algorithm

    参考资料

    1. Operating System:Design and Implementation,Third Edition
    展开全文
  • 存储管理的四大基本功能 1、内存分配与回收 当有作业进入系统时,存储管理模块就会根据当前内存情况来分配内存给它;当作业完成后,就会回收作业占用的内存,将这部分内存设置为可分配状态。 分配方式主要有两种: ...

    存储管理的四大基本功能

    1、内存分配与回收

    当有作业进入系统时,存储管理模块就会根据当前内存情况来分配内存给它;当作业完成后,就会回收作业占用的内存,将这部分内存设置为可分配状态。

    分配方式主要有两种:

    静态分配:作业在运行之前,已经明确所需内存的大小,并且一次性分配;作业在运行的时候,不可以重新申请或移动内存。

    动态分配:作业在运行期间,可以根据需要动态申请内存。比静态分配灵活,并且能够提高内存的利用率,避免因静态分配导致不必要的信息加载到内存中。

    2、地址重定位

    实现程序的逻辑地址和物理地址转换,并根据物理地址重定位到物理空间。

    程序中,基本都是用符号名来访问存储单元的。而符号名存储的是逻辑地址,而逻辑地址可以转化为物理地址,最后可以通过物理地址直接定位存储单元。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QpBvY0Ia-1629033009669)(https://camo.githubusercontent.com/2b4ffb6c70a5ce8c704db0e2a13e300a812052fe48545c6755cc732d69e1f46d/68747470733a2f2f6d6d62697a2e717069632e636e2f6d6d62697a5f706e672f42574c624b395067714b334339425a7a50366961696255365948477165724b4844375775306d4b6e69634d73696369634a6172356d4c554a363066784f6963436b33514c38576d435633704b366f49365752496157425563455055412f3634303f77785f666d743d706e672674703d7765627026777866726f6d3d352677785f6c617a793d312677785f636f3d31)]

    其中重定位一共有两种方式:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pYxeXIsU-1629033009674)(https://camo.githubusercontent.com/e5b9b373ed4880855cb3296d51b8494add41e3e0b2b2f15398a10d2fb88e84cf/68747470733a2f2f6d6d62697a2e717069632e636e2f6d6d62697a5f706e672f42574c624b395067714b334339425a7a50366961696255365948477165724b4844376c33433773725038566b79457056474b58726f4a524a4b777377464275723078723458436b537036345545347854514d6f53387177412f3634303f77785f666d743d706e672674703d7765627026777866726f6d3d352677785f6c617a793d312677785f636f3d31)]

    3、存储保护

    存储保护是为了防止程序越界访问、破坏其他程序或系统的存储区。较为普遍的存储保护方法是:硬件的界限存储器保护法,并且还分为两种实现方法。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QJ6gSARp-1629033009677)(https://camo.githubusercontent.com/a09cdf8110364b59c694a21f467c9cfb7e19bf855808896fcec2017fde902284/68747470733a2f2f6d6d62697a2e717069632e636e2f6d6d62697a5f706e672f42574c624b395067714b334339425a7a50366961696255365948477165724b48443751496575736143574e4477754d4e6a6962416f3166424d394955364b3832706f775968326962716d54775555674953335a4968426769616961512f3634303f77785f666d743d706e672674703d7765627026777866726f6d3d352677785f6c617a793d312677785f636f3d31)]

    4、虚拟存储

    程序的局部性分为:时间和空间的局部性。

    时间局部性:某条指令被执行,那么在不久的将来也会被再次执行。

    空间局部性:一旦程序访问某个存储单元的数据,那么不久的将来,这个存储单元附近的存储单元也可能会被访问。

    由于程序的局部性原理,很多数据没有必要全部加载到内存。因此就将那些不必要的数据暂存在外存中,等到需要的时候再调入到内存中。这部分外存就充当虚拟内存,也叫虚拟存储。

    展开全文
  • Android 内存管理机制

    千次阅读 多人点赞 2018-09-03 14:41:45
    本文主要包括三大部分内容: 内存管理基础:从整个计算机领域... Android的内存管理相关知识:Android又不同于Linux,它是一个移动操作系统,因此其内存管理上也有自己的特性,这一部分详细讲述Android的内存管理...

    本文主要包括三大部分内容:

    内存管理基础:从整个计算机领域简述主要的内存管理技术。
    Linux的内存管理机制:Android毕竟是基于Linux内核实现的操作系统,因此有必要了解一下Linux的内存管理机制。
    Android的内存管理相关知识:Android又不同于Linux,它是一个移动操作系统,因此其内存管理上也有自己的特性,这一部分详细讲述Android的内存管理相关知识,包括 内存管理机制进程管理

    内存管理基础

    概述

    CPU只能访问其寄存器(Register)和内存(Memory), 无法直接访问硬盘(Disk)。 存储在硬盘上的数据必须首先传输到内存中才能被CPU访问。从访问速度来看,对寄存器的访问非常快,通常为1纳秒; 对内存的访问相对较慢,通常为100纳秒(使用缓存加速的情况下);而对硬盘驱动器的访问速度最慢,通常为10毫秒。

    寄存器(Register):CPU内部的高速存储区域

    当一个程序加载到内存中时,它由四个内存区域组成:

    • 堆栈(Stack):存储由该程序的每个函数创建的临时变量
    • 堆(Heap):该区域特别适用于动态内存分配
    • 数据(Data):存储该程序的全局变量和静态变量
    • 代码(Code):存储该程序的指令

    主要的内存管理技术

    • Base and limit registers(基址寄存器和界限寄存器)
    • Virtual memory(虚拟内存)
    • Swapping(交换)
    • Segmentation(分段)
    • Paging(分页)
    Base and limit registers(基址寄存器和界限寄存器)

    必须限制进程,以便它们只能访问属于该特定进程的内存位置。

    每个进程都有一个基址寄存器和限制寄存器:

    • 基址寄存器保存最小的有效存储器地址
    • 限制寄存器指定范围的大小

    例如,process 2的有效内存地址是300040到420940

    那么每个来自用户进程的内存访问都将首先针对这两个寄存器进行一次检查:

    操作系统内核可以访问所有内存位置,因为它需要管理整个内存。

    Virtual memory(虚拟内存)

    虚拟内存(VM)是OS为内存管理提供的基本抽象。

    • 所有程序都使用虚拟内存地址
    • 虚拟地址会被转换为物理地址
    • 物理地址表示数据的实际物理位置
    • 物理位置可以是内存或磁盘

    虚拟地址到物理地址的转换由存储器管理单元(MMU - Memory Management Unit)处理。MMU使用重定位寄存器(relocation register),其值在硬件级别上被添加到每个内存请求中。

    Swapping(交换)

    交换是一种可以暂时将进程从内存交换到后备存储,而之后又可以将其返回内存以继续执行的技术。

    后备存储通常是一个硬盘驱动器,其访问速度快,且大小足以存储内存映像的副本。

    如果没有足够的可用内存来同时保留内存中的所有正在运行的进程,则某些当前未使用CPU的进程可能会被交换到后备存储中。

    交换是一个非常缓慢的过程。 主要耗时部分是数据传输。例如,如果进程占用10MB内存并且后备存储的传输速率为40MB/秒,则需要0.25秒来进行数据传输。 再加上将数据交换回内存的时间,总传输时间可能是半秒,这是一个巨大的延迟,因此,有些操作系统已经不再使用交换了。

    Segmentation(分段)

    分段是一种将内存分解为逻辑片段的技术,其中每个片段代表一组相关信息。 例如,将每个进程按照堆栈,堆,数据以及代码分为不同的段,还有OS内核的数据段等。

    将内存分解成较小的段会增加寻找空闲内存的机会。

    每个段都有一对寄存器:

    • 基址寄存器:包含段驻留在内存中的起始物理地址
    • 限制寄存器:指定段的长度

    **段表(Segment table)**存储每个段的基址和限制寄存器信息。

    使用分段时,虚拟内存地址是一对:<段号,偏移量>

    • 段号(Segment Number):用作段表的索引以查找特定条目
    • 偏移量(Offset):首先与限制寄存器进行比较,然后与基址结合以计算物理内存地址

    Paging(分页)

    有时可用内存被分成许多小块,其中没有一块足够大以满足下一个内存需求,然而他们的总和却可以。这个问题被称为碎片(Fragmentation),许多内存分配策略都会受其影响。

    分页是一种内存管理技术,它允许进程的物理内存不连续。它通过在称为页面(Page)的相同大小的块中分配内存来消除碎片问题,是目前比较优秀的内存管理技术。

    分页将物理内存划分为多个大小相等的块,称为帧(Frame)。并将进程的逻辑内存空间也划分为大小相等的块,称为页面(Page)

    任何进程中的任何页面都可以放入任何可用的帧中。

    **页表(Page Table)**用于查找此刻存储特定页面的帧。

    使用分页时,虚拟内存地址是一对:<页码,偏移量>

    • 页码(Page Number):用作页表的索引,以查找此页面的条目
    • 偏移量(Offset):与基址相结合,以定义物理内存地址

    举一个分页地址转换的例子:

    虚拟内存地址为0x13325328,页表项0x13325包含的值是0x03004,那么物理地址是什么?

    答案:
    物理地址是0x03004328
    页码为0x13325,偏移量为0x328
    相应的帧号是0x03004

    Linux的内存管理机制

    在Linux系统下,监控内存常用的命令是free、top等,下面是一个free命令的执行结果:

    要了解Linux的内存管理,首先要明白上例中各个名词的意义:

    • total:物理内存的总大小。
    • used:已经使用的物理内存多小。
    • free:空闲的物理内存值。
    • shared:多个进程共享的内存值。
    • buffers / cached:用于磁盘缓存的大小(这部分是从物理内存中划出来的)。
    • 第二行Mem:代表物理内存使用情况。
    • 第三行(-/+ buffers/cached):代表磁盘缓存使用状态。
    • 第四行:Swap表示交换空间内存使用状态(这部分实际上是从磁盘上虚拟出来的逻辑内存)。

    free命令输出的内存状态,可以从两个角度来看:内核角度、应用层角度。

    1.从内核角度来查看内存的状态:

    就是内核目前可以直接分配到,不需要额外的操作,即free命令第二行 Mem 的输出。从上例中可见,41940 + 16360492 = 16402432,也就是说Mem行的 free + used = total,注意,这里的free并不包括buffers和cached。

    2.从应用层角度来查看内存的状态:

    也就是Linux上运行的程序可以使用的内存大小,即free命令第三行 -/+ buffers/cache 的输出。再来做一个计算41940+(465404+12714880)=13222224,即Mem行的free + buffers + cached = -/+ buffers/cache行的free,也就是说应用可用的物理内存值是Mem行的free、buffers和cached三者之和,可见-/+ buffers/cache行的free是包括buffers和cached的。

    对于应用程序来说,buffers/cached占有的内存是可用的,因为buffers/cached是为了提高文件读取的性能,当应用程序需要用到内存的时候,buffers/cached会很快地被回收,以供应用程序使用。

    物理内存和虚拟内存

    物理内存就是系统硬件提供的内存大小,是真正的内存。在linux下还有一个虚拟内存的概念,虚拟内存就是为了满足物理内存的不足而提出的策略,它是利用磁盘空间虚拟出的一块逻辑内存,用作虚拟内存的磁盘空间被称为 交换空间(Swap Space)

    linux的内存管理采取的是分页存取机制,为了保证物理内存能得到充分的利用,内核会在适当的时候将物理内存中不经常使用的数据块自动交换到虚拟内存中,而将经常使用的信息保留到物理内存。而进行这种交换所遵循的依据是“LRU”算法(Least Recently Used,最近最少使用算法)。

    Buffers和Cached有什么用

    在任何系统中,文件的读写都是一个耗时的操作,当应用程序需要读写文件中的数据时,操作系统先分配一些内存,将数据从磁盘读入到这些内存中,然后应用程序读写这部分内存数据,之后系统再将数据从内存写到磁盘上。如果是大量文件读写甚至重复读写,系统读写性能就变得非常低下,在这种情况下,Linux引入了缓存机制。

    buffers与cached都是从物理内存中分离出来的,主要用于实现磁盘缓存,用来保存系统曾经打开过的文件以及文件属性信息,这样当操作系统需要读取某些文件时,会首先在buffers与cached内存区查找,如果找到,直接读出传送给应用程序,否则,才从磁盘读取,通过这种缓存机制,大大降低了对磁盘的IO操作,提高了操作系统的数据访问性能。而这种磁盘高速缓存则是基于两个事实:第一,内存访问速度远远高于磁盘访问速度;第二,数据一旦被访问,就很有可能短期内再次被访问。

    另外,buffers与cached缓存的内容也是不同的。buffers是用来缓冲块设备做的,它只记录文件系统的元数据(metadata)以及 tracking in-flight pages,而cached是用来给文件做缓冲。更通俗一点说:buffers主要用来存放目录里面有什么内容,文件的属性以及权限等等。而cached直接用来记忆我们打开过的文件和程序

    为了验证我们的结论是否正确,可以通过vi打开一个非常大的文件,看看cached的变化,然后再次vi这个文件,感觉一下是不是第二次打开的速度明显快于第一次?

    接着执行下面的命令:

    find /* -name  *.conf
    

    看看buffers的值是否变化,然后重复执行find命令,看看两次显示速度有何不同。

    Linux内存管理的哲学

    Free memory is wasted memory.

    Linux的哲学是尽可能多的使用内存,减少磁盘IO,因为内存的速度比磁盘快得多。Linux总是在力求缓存更多的数据和信息,内存不够时,将一些不经常使用的数据转移到交换分区(Swap Space)中以释放更多可用物理内存,当然,如果交换分区的数据再次被读写时,又会被转移到物理内存中,这种设计思路提高了系统的整体性能。而Windows的处理方式是,内存和虚拟内存一起使用,不是以内存操作为主,结果就是IO的负担比较大,可能拖慢处理速度。

    Linux和Windows在内存管理机制上的区别

    在Linux系统使用过程中,你会发现,无论你的电脑内存配置多么优越,仍然不时的发生可用内存吃紧的现象,感觉内存不够用了,其实不然。这是Linux内存管理的优秀特性,无论物理内存有多大,Linux都将其充分利用,将一些程序调用过的硬盘数据缓存到内存,利用内存读写的高速性提高系统的数据访问性能。而Window只在需要内存时,才为应用分配内存,不能充分利用大容量的内存空间。换句话说,每增加一些内存,Linux都能将其利用起来,充分发挥硬件投资带来的好处,而Windows只将其作为摆设。

    所以说,一般我们不需要太关注Linux的内存占用情况,而如果Swap占用率一直居高不下的话,就很有可能真的是需要扩展内存了

    Android的内存管理机制

    Android使用虚拟内存和分页,不支持交换

    垃圾收集

    无论是ART还是Dalvik虚拟机,都和众多Java虚拟机一样,属于一种托管内存环境(程序员不需要显示的管理内存的分配与回收,交由系统自动管理)。托管内存环境会跟踪每个内存分配, 一旦确定程序不再使用一块内存,它就会将其释放回堆中,而无需程序员的任何干预。 回收托管内存环境中未使用内存的机制称为垃圾回收

    垃圾收集有两个目标:

    • 在程序中查找将来无法访问的数据对象;
    • 回收这些对象使用的资源。

    Android的垃圾收集器不带压缩整理功能(Compact),即不会对Heap做碎片整理。

    Android的内存堆是分代式(Generational)的,意味着它会将所有分配的对象进行分代,然后分代跟踪这些对象。 例如,最近分配的对象属于年轻代(Young Generation)。 当一个对象长时间保持活动状态时,它可以被提升为年老代(Older Generation),之后还能进一步提升为永久代(Permanent Generation)

    每一代的对象可占用的内存总量都有其专用上限。 每当一代开始填满时,系统就会执行垃圾收集事件以试图释放内存。 垃圾收集的持续时间取决于它在收集哪一代的对象以及每一代中有多少活动对象

    虽然垃圾收集速度非常快,但它仍然会影响应用程序的性能。通常情况下你不需要控制代码中何时执行垃圾收集事件。 系统有一组用于确定何时执行垃圾收集的标准。 满足条件后,系统将停止执行当前进程并开始垃圾回收。 如果在像动画或音乐播放这样的密集处理循环中发生垃圾收集,则会增加处理时间。 这种增加可能会导致你的应用程序中的代码执行超过建议的16ms阈值。

    为实现高效,流畅的帧渲染,Android建议绘制一帧的时间不要超过16ms。

    此外,你的代码可能会执行各种工作,这些工作会导致垃圾收集事件更频繁地发生,或使其持续时间超过正常范围。 例如,如果在Alpha混合动画的每个帧期间在for循环的最内部分配多个对象,则大量的对象就会污染内存堆。 此时,垃圾收集器会执行多个垃圾收集事件,并可能降低应用程序的性能。

    共享内存

    Android可以跨进程共享RAM页面(Pages)。 它可以通过以下方式实现:

    • 每个应用程序进程都是从名为Zygote的现有进程分叉(fork)出来的。 Zygote进程在系统引导并加载framework代码和资源(例如Activity Themes)时启动。 要启动新的应用程序进程,系统会fork Zygote进程,然后在新进程中加载并运行应用程序的代码。 这种方法允许在所有应用程序进程中共享大多数的为framework代码和资源分配的RAM页面

    • 大多数静态数据都被映射到一个进程中。 该技术允许在进程之间共享数据,并且还允许在需要时将其Page out。这些静态数据包括:Dalvik代码(通过将其置于预链接的.odex文件中进行直接的memory-mapping),app资源(通过将资源表设计为可以mmap的结构并通过对齐APK的zip条目) 和传统的项目元素,如.so文件中的本地代码。
    • 在许多地方,Android使用显式分配的共享内存区域(使用ashmem或gralloc)在进程间共享相同的动态RAM。 例如,Window surface在应用程序和屏幕合成器之间使用共享内存,而游标缓冲区在Content Provider和客户端之间使用共享内存。

    分配和回收应用的内存

    Android为每个进程分配内存的时候,采用了弹性分配方式,也就是刚开始并不会一下分配很多内存给每个进程,而是给每一个进程分配一个“够用”的虚拟内存范围。这个范围是根据每一个设备实际的物理内存大小来决定的,并且可以随着应用后续需求而增加,但最多也只能达到系统为每个应用定义的上限。

    堆的逻辑大小与其使用的物理内存总量并不完全相同。 在检查应用程序的堆时,Android会计算一个名为“比例集大小”(PSS)的值,该值会考虑与其他进程共享的脏页面和干净页面,但其总量与共享该RAM的应用程序数量成正比。 此PSS总量就是系统认为是你的物理内存占用量。

    Android会在内存中尽量长时间的保持应用进程,即使有些进程不再使用了。这样,当用户下次启动应用的时候,只需要恢复当前进程就可以了,不需要重新创建进程,进而减少应用的启动时间。只有当Android系统发现内存不足,而其他为用户提供更紧急服务的进程又需要内存时,Android就会决定关闭某些进程以回收内存。关于这部分内容,稍后再细说。

    限制应用的内存

    为了维护高效的多任务环境,Android为每个应用程序设置了堆大小的硬性限制。 该限制因设备而异,取决于设备总体可用的RAM。 如果应用程序已达到该限制并尝试分配更多内存,则会收到 OutOfMemoryError

    在某些情况下,你可能希望查询系统以准确确定当前设备上可用的堆空间大小,例如,确定可以安全地保留在缓存中的数据量。 你可以通过调用 getMemoryClass() 来查询系统中的这个数字。 此方法返回一个整数,指示应用程序堆可用的兆字节数。

    切换应用

    当用户在应用程序之间切换时,Android会将非前台应用程序(即用户不可见或并没有运行诸如音乐播放等前台服务的进程)缓存到一个最近最少使用缓存(LRU Cache)中。例如,当用户首次启动应用程序时,会为其创建一个进程; 但是当用户离开应用程序时,该进程不会退出。 系统会缓存该进程。 如果用户稍后返回应用程序,系统将重新使用该进程,从而使应用程序切换更快。

    如果你的应用程序具有缓存进程并且它保留了当前不需要的内存,那么即使用户未使用它,你的应用程序也会影响系统的整体性能。 当系统内存不足时,就会从最近最少使用的进程开始,终止LRU Cache中的进程。另外,系统还会综合考虑保留了最多内存的进程,并可能终止它们以释放RAM。

    当系统开始终止LRU Cache中的进程时,它主要是自下而上的。 系统还会考虑哪些进程占用更多内存,因为在它被杀时会为系统提供更多内存增益。 因此在整个LRU列表中消耗的内存越少,保留在列表中并且能够快速恢复的机会就越大。

    Android对Linux系统的内存管理机制进行的优化

    Android对内存的使用方式同样是“尽最大限度的使用”,这一点继承了Linux的优点。只不过有所不同的是,Linux侧重于尽可能多的缓存磁盘数据以降低磁盘IO进而提高系统的数据访问性能,而Android侧重于尽可能多的缓存进程以提高应用启动和切换速度。Linux系统在进程活动停止后就结束该进程,而Android系统则会在内存中尽量长时间的保持应用进程,直到系统需要更多内存为止。这些保留在内存中的进程,通常情况下不会影响系统整体运行速度,反而会在用户再次激活这些进程时,加快进程的启动速度,因为不用重新加载界面资源了,这是Android标榜的特性之一。所以,Android现在不推荐显式的“退出”应用

    那为什么内存少的时候运行大型程序会慢呢,原因是:在内存剩余不多时打开大型程序会触发系统自身的进程调度策略,这是十分消耗系统资源的操作,特别是在一个程序频繁向系统申请内存的时候。这种情况下系统并不会关闭所有打开的进程,而是选择性关闭,频繁的调度自然会拖慢系统。

    Android中的进程管理

    说到Android的内存管理,就不得不提到进程管理,因为进程管理确确切切的影响着系统内存。在了解进程管理之前,我们首先了解一些基础概念。

    当某个应用组件启动且该应用没有运行其他任何组件时,Android 系统会使用单个执行线程为应用启动新的 Linux 进程。默认情况下,同一应用的所有组件在相同的进程和线程(称为“主”线程)中运行。 如果某个应用组件启动且该应用已存在进程(因为存在该应用的其他组件),则该组件会在此进程内启动并使用相同的执行线程。 但是,你也可以安排应用中的其他组件在单独的进程中运行,并为任何进程创建额外的线程。

    Android应用模型的设计思想取自Web 2.0的Mashup概念,是基于组件的应用设计模式。在该模型下,每个应用都由一系列的组件搭建而成,组件通过应用的配置文件描述功能。Android系统依照组件的配置信息,了解各个组件的功能并进行统一调度。这就意味着,来自不同应用的组件可以有机地结合在一起,共同完成任务,各个Android应用,只有明确的组件边界,而不再有明确的进程边界和应用边界。这种设计,也令得开发者无需耗费精力去重新开发一些附属功能,而是可以全身心地投入到核心功能的开发中。这样不但提高了应用开发的效率,也增强了用户体验(比如电子邮件中选择图片作为附件的功能,可以直接调用专门的图片应用的功能,不用自己从头开发)。

    系统不会为每个组件实例创建单独的线程。运行于同一进程的所有组件均在 UI 线程中实例化,并且对每个组件的系统调用均由该线程进行分派。 因此,响应系统回调的方法(例如,报告用户操作的 onKeyDown() 或生命周期回调方法)始终在进程的 UI 线程中运行(四大组件的各个生命周期回调方法都是在UI线程中触发的)。

    进程的生命周期

    Android的一个不寻常的基本特征是应用程序进程的生命周期并非是由应用本身直接控制的。相反,进程的生命周期是由系统决定的,系统会权衡每个进程对用户的相对重要程度,以及系统的可用内存总量来确定。比如说相对于终止一个托管了正在与用户交互的Activity的进程,系统更可能终止一个托管了屏幕上不再可见的Activity的进程,否则这种后果是可怕的。因此,是否终止某个进程取决于该进程中所运行组件的状态。Android会有限清理那些已经不再使用的进程,以保证最小的副作用。

    作为应用开发者,了解各个应用组件(特别是Activity、Service和BroadcastReceiver)如何影响应用进程的生命周期非常重要。不正确的使用这些组件,有可能导致系统在应用执行重要工作时终止进程。

    举个常见的例子, BroadcastReceiver 在其 onReceive() 方法中接收到Intent时启动一个线程,然后从该函数返回。而一旦返回,系统就认为该 BroadcastReceiver 不再处于活动状态,因此也就不再需要其托管进程(除非该进程中还有其他组件处于活动状态)。这样一来,系统就有可能随时终止进程以回收内存,而这也最终会导致运行在进程中的线程被终止。此问题的解决方案通常是从 BroadcastReceiver 中安排一个 JobService ,以便系统知道在该进程中仍有活动的工作。

    为了确定在内存不足时终止哪些进程,Android会根据进程中正在运行的组件以及这些组件的状态,将每个进程放入“重要性层次结构”中。必要时,系统会首先杀死重要性最低的进程,以此类推,以回收系统资源。这就相当于为进程分配了优先级的概念。

    进程优先级

    Android中总共有5个进程优先级(按重要性降序):

    Foreground Process:前台进程(正常不会被杀死)

    用户当前操作所必需的进程。有很多组件能以不同的方式使得其所在进程被判定为前台进程。如果一个进程满足以下任一条件,即视为前台进程:

    • 托管用户正在交互的 Activity(已调用 Activity 的 onResume() 方法)
    • 托管某个 Service,后者绑定到用户正在交互的 Activity
    • 托管正执行一个生命周期回调的 Service(onCreate()、onStart() 或 onDestroy())
    • 托管正执行其 onReceive() 方法的 BroadcastReceiver

    通常,在任意给定时间前台进程都为数不多。只有在内存不足以支持它们同时继续运行这一万不得已的情况下,系统才会终止它们。 此时,设备往往已达到内存分页状态,因此需要终止一些前台进程来确保用户界面正常响应。

    Visible Process:可见进程(正常不会被杀死)

    没有任何前台组件、但仍会影响用户在屏幕上所见内容的进程。杀死这类进程也会明显影响用户体验。 如果一个进程满足以下任一条件,即视为可见进程:

    • 托管不在前台、但仍对用户可见的 Activity(已调用其 onPause() 方法)。例如,启动了一个对话框样式的前台 activity ,此时在其后面仍然可以看到前一个Activity。

      运行时权限对话框就属于此类。
      考虑一下,还有哪种情况会导致只触发onPause而不触发onStop?

    • 托管通过 Service.startForeground() 启动的前台Service。

      Service.startForeground():它要求系统将它视为用户可察觉到的服务,或者基本上对用户是可见的。

    • 托管系统用于某个用户可察觉的特定功能的Service,比如动态壁纸、输入法服务等等。

    可见进程被视为是极其重要的进程,除非为了维持所有前台进程同时运行而必须终止,否则系统不会终止这些进程。如果这类进程被杀死,从用户的角度看,这意味着当前 activity 背后的可见 activity 会被黑屏代替。

    Service Process:服务进程(正常不会被杀死)

    正在运行已使用 startService() 方法启动的服务且不属于上述两个更高类别进程的进程。尽管服务进程与用户所见内容没有直接关联,但是它们通常在执行一些用户关心的操作(例如,后台网络上传或下载数据)。因此,除非内存不足以维持所有前台进程和可见进程同时运行,否则系统会让服务进程保持运行状态。

    已经运行很久(例如30分钟或更久)的Service,有可能被降级,这样一来它们所在的进程就可以被放入Cached LRU列表中。这有助于避免一些长时间运行的Service由于内存泄漏或其他问题而消耗过多的RAM,进而导致系统无法有效使用缓存进程的情况。

    Background / Cached Process:后台进程(可能随时被杀死)

    这类进程一般会持有一个或多个目前对用户不可见的 Activity (已调用 Activity 的 onStop() 方法)。它们不是当前所必须的,因此当其他更高优先级的进程需要内存时,系统可能随时终止它们以回收内存。但如果正确实现了Activity的生命周期,即便系统终止了进程,当用户再次返回应用时也不会影响用户体验:关联Activity在新的进程中被重新创建时可以恢复之前保存的状态。

    在一个正常运行的系统中,缓存进程是内存管理中唯一涉及到的进程:一个运行良好的系统将始终具有多个缓存进程(为了更高效的切换应用),并根据需要定期终止最旧的进程。只有在非常严重(并且不可取)的情况下,系统才会到达这样一个点,此时所有的缓存进程都已被终止,并且必须开始终止服务进程。

    Android系统回收后台进程的参考条件
    LRU算法:自下而上开始终止,先回收最老的进程。越老的进程近期内被用户再次使用的几率越低。杀死的进程越老,对用户体验的影响就越小。
    回收收益:系统总是倾向于杀死一个能回收更多内存的进程,因为在它被杀时会为系统提供更多内存增益,从而可以杀死更少的进程。杀死的进程越少,对用户体验的影响就越小。换句话说,应用进程在整个LRU列表中消耗的内存越少,保留在列表中并且能够快速恢复的机会就越大。

    这类进程会被保存在一个伪LRU列表中,系统会优先杀死处于列表尾部(最老)的进程,以确保包含用户最近查看的 Activity 的进程最后一个被终止。这个LRU列表排序的确切策略是平台的实现细节,但通常情况下,相对于其他类型的进程,系统会优先尝试保留更有用的进程(比如托管用户主应用程序的进程,或者托管用户看到的最后一个Activity的进程,等等)。还有其他一些用于终止进程的策略:对允许的进程数量硬限制,对进程可以持续缓存的时间量的硬限制,等等。

    在一个健康的系统中,只有缓存进程或者空进程会被系统随时终止,如果服务进程,或者更高优先级的可见进程以及前台进程也开始被系统终止(不包括应用本身糟糕的内存使用导致OOM),那就说明系统运行已经处于一个亚健康甚至极不健康的状态,可用内存已经吃紧。

    Empty Process:空进程(可以随时杀死)

    不含任何活跃组件的进程。保留这种进程的的唯一目的是用作缓存(为了更加有效的使用内存而不是完全释放掉),以缩短下次启动应用程序所需的时间,因为启动一个新的进程也是需要代价的。只要有需要,Android会随时杀死这些进程。

    内存管理中对于前台/后台应用的定义,与用于Service限制目的的后台应用定义不同。从Android 8.0开始,出于节省系统资源、优化用户体验、提高电池续航能力的考量,系统进行了前台/后台应用的区分,对于后台service进行了一些限制。在该定义中,如果满足以下任意条件,应用将被视为处于前台:

    • 具有可见 Activity(不管该 Activity 已启动还是已暂停)。
    • 具有前台 Service。
    • 另一个前台应用已关联到该应用(不管是通过绑定到其中一个 Service,还是通过使用其中一个内容提供程序)。 例如,如果另一个应用绑定到该应用的 Service,那么该应用处于前台:
      IME
      壁纸 Service
      通知侦听器
      语音或文本 Service
      如果以上条件均不满足,应用将被视为处于后台。详见后台Service限制

    Android系统如何评定进程的优先级

    根据进程中当前活动组件的重要程度,Android 会将进程评定为它可能达到的最高级别。例如,如果某进程同时托管着 Service 和可见 Activity,则会将此进程评定为可见进程,而不是服务进程。

    此外,一个进程的级别可能会因其他进程对它的依赖而有所提高,即服务于另一进程的进程其级别永远不会低于其所服务的进程。 例如,如果进程 A 中的内容提供程序为进程 B 中的客户端提供服务,或者如果进程 A 中的服务绑定到进程 B 中的组件,则进程 A 始终被视为至少与进程 B 同样重要。

    由于运行服务的进程其级别高于托管后台 Activity 的进程,因此,在 Activity 中启动一个长时间运行的操作时,最好为该操作启动服务,而不是简单地创建工作线程,当操作有可能比 Activity 更加持久时尤要如此。例如,一个文件上传的操作就可以考虑使用服务来完成,这样一来,即使用户退出 Activity,仍可在后台继续执行上传操作。使用服务可以保证,无论 Activity 发生什么情况,该操作至少具备“服务进程”优先级。 同理, BroadcastReceiver 也应使用服务,而不是简单地将耗时冗长的操作放入线程中。

    Home键退出和返回键退出的区别

    Home键退出,程序保留状态为后台进程;而返回键退出,程序保留状态为空进程,空进程更容易被系统回收。Home键其实主要用于进程间切换,返回键则是真正的退出程序。

    从理论上来讲,无论是哪种情况,在没有任何后台工作线程(即便应用处于后台,工作线程仍然可以执行)的前提下,被置于后台的进程都只是保留他们的运行状态,并不会占用CPU资源,所以也不耗电。只有音乐播放软件之类的应用需要在后台运行Service,而Service是需要占用CPU时间的,此时才会耗电。所以说没有带后台服务的应用是不耗电也不占用CPU时间的,没必要关闭,这种设计本身就是Android的优势之一,可以让应用下次启动时更快。然而现实是,很多应用多多少少都会有一些后台工作线程,这可能是开发人员经验不足导致(比如线程未关闭或者循环发送的Handler消息未停止),也可能是为了需求而有意为之,导致整个Android应用的生态环境并不是一片干净。

    作为用户,你需要手动管理内存吗?

    你有“内存使用率过高”恐慌症吗?

    无论是使用桌面操作系统还是移动操作系统,很多人都喜欢随时关注内存,一旦发现内存使用率过高就难受,忍不住的要杀进程以释放内存。这种习惯很大程度上都是源自Windows系统,当然这在Windows下也确实没错。然而很多人在使用Linux系统时仍然有这个习惯,甚至到了Android系统下,也改不掉(尤其是Android手机刚出现的几年),Clean Master等各种清理软件铺天盖地。毫不客气的说,Windows毒害了不少人!当然,这也不能怪Windows,毕竟Windows的普及率太高了,而大部分普通用户(甚至一些计算机相关人员)又不了解Windows和Linux在内存管理方面的差别。

    何时需要清理手机的RAM?

    考虑到许多手机厂商都内置了“清理”功能,那这个东西可能也有些道理。事实上,关闭应用程序以节省内存的做法,仅在少数情况下是值得尝试的 —— 当应用崩溃或无法正常运行时。比如以下情况:

    • 你的微信在启动时需要加载很久
    • 某个应用启动时闪退或者运行过程中闪退
    • 系统响应速度非常缓慢

    这些症状可能非常多样化,甚至原因不明的手机发热也可能是由于某个崩溃的应用造成的。

    管理你的手机RAM:结论

    究竟需不需要手动清空内存?答案是:No!

    清空内存意味着你需要不断重启应用,这需要花费时间和电量,甚至会缩短电池寿命。内存占用高其实并非是一件坏事,甚至是需要的。因为Android是基于Linux内核的操作系统,而Linux的内存哲学是:

    Free memory is wasted memory.

    你只需要在手机明显变慢时采取行动。一般来说,系统的自动RAM管理才是最快最高效的,也是Android标榜的优势之一。关闭应用可能释放一些内存,但却对高效使用内存毫无作用。

    Leave the memory management to Android, and it will leave the fun to you.

    参考资料

    浅谈Linux的内存管理机制
    Processes and Threads Overview
    Process and Application Lifecycle
    Overview of Memory Management
    RAM management on Android: why you shouldn’t clear memory

    展开全文
  • iOS 内存管理基本原则

    千次阅读 2016-05-07 19:33:55
    我们知道objc中创建对象是存放在堆中的(基本数据类型除外,是由系统自己管理,并存放在栈中),系统不会自动释放堆中的...苹果公司共推出了3中内存管理机制:ARC(自动内存管理)、MRC(手动内存管理)、自动释放池。

    我们知道objc中创建对象是存放在堆中的(基本数据类型除外,是由系统自己管理,并存放在栈中),系统不会自动释放堆中的内存。如果创建完的对象存放在堆中后并使用完没有得到及时的释放,会占用的内存。但是objc没有GC(垃圾回收机制),因此需要开发者手动管理内存。苹果公司共推出了3中内存管理机制:ARC(自动内存管理)、MRC(手动内存管理)、自动释放池。下面根据以下几个方面讨论一下内存管理。

    1.内存管理的目的

    a.不释放或者覆盖正在使用的内存空间;

    b.释放已经不需要的内存空间,以防治内存泄漏。

    2.内存管理的一些概念

    ARC

    ARC是苹果公司iOS5推出的新功能,代码中自动加入了retain/release,原先需要手动添加的用来处理内存管理的引用计数的代码可以自动地由编译器完成了(通过指定的语法,让编译器在编译代码时,自动生成实例的引用计数管理部分代码。)。

    好处:

    1代码比以前需要手动管理内存,简单了,不需要时刻担心内存泄漏;
    2
    代码高速化,使用编译器来管理内存引用计数,减少了低效代码的可能性。
    坏处:

    1)一些老代码,以及以往的第三方库,使用起来比较麻烦。

    MRC

    MRC是手动内存管理。与其对变量的管理相关的方法有:retain,release和autorelease。retain和release方法操作的是引用记数,当引用记数为零时,便自动释放内存。

    (1retain,该方法的作用是将内存数据的所有权附给另一指针变量,引用数加1,即retainCount+= 1;
    (2
    release,该方法是释放指针变量对内存数据的所有权,引用数减1,即retainCount-= 1;
    (3)autorelease,该方法是将该对象内存的管理放到autoreleasepool中。

    自动释放池

    自动释放池(Autorelease pool)是OC的一种内存自动回收机制,可以将一些临时变量通过自动释放池来回收统一释放。自动释放池本事销毁的时候,池子里面所有的对象都会做一次release操作。与之对应的方法是autorelease任何OC对象只要调用autorelease方法,就会把该对象放到离自己最近的自动释放池中(栈顶的释放池)。

    引用计数

    任何一个oc对象都会有一个这样的属性retainCount,这个retainCount就是引用计数,当对象被创建的时候,该对象的引用计数为初始化值1,当retainCount为0时,会被该对象所占内存会被释放,使用retain的时候引用计数为+1。

    3.内存管理的原则

    内存管理的原则是:谁创建,谁释放;谁引用,谁管理。即当你使用new、alloc、copy或者mutablecopy创建对象的时候,该对象的引用计数为初始化值1,当你使用retain向对象发送消息时,你将拥有该对象的控制权,并且引用计数为+1,当你不在使用该对象的时候,你需要release或者autorelease释放该对象,使之引用计数-1,当引用计数为0时,该对象将被释放。

    4.实际中一些使用操作

    a.ARC和MRC混编

    现在的开发过程中居多使用ARC,但是常常使用一些MRC的第三方的库,这时候我们需要使用-fno-objc-arc来进行标示,如果使用MRC混编ARC的时候,需要使用-fno-objc-mrc来标示ARC的文件。

    5.面试中遇到的一些关于内存管理的问题

    a.简述你理解的内存管理;

    简述内存管理的原则,以及内存管理的方法就行。

    b.给出一段代码来让你说出引用计数

    知道使用new、alloc、copy或者mutable copy,引用计数为初始值1,再使用retain的话,引用计数为+1,使用release或者autorelease会使引用计数-1。然后根据实际情况来说明基本这种题soso的搞定。

    展开全文
  • 存储器一直都是计算机系统的重要组成部分。近年来,随着技术的发展,虽然存储器的容量一直在不断扩大,但是仍不能满足现代软件...本文对存储器管理功能管理对象,基本模式进行讨论,并介绍了虚拟存储器的概念...
  • 内存管理方式-基本分页管理的详细说明
  • 日期 内核版本 架构 作者 GitHub CSDN 2016-06-14 ...在内存管理的上下文中, 初始化(initialization)可以有多种含义. 在许多CPU上, 必须显式设置适用于Linux内核的内存模型. 例如在x86_32上需要切换
  • 内存覆盖与内存交换 ...覆盖的基本思想是:由于程序运行时并非任何时候都要访问程序及数据的各个部分(尤其是大程序),因此可以把用户空间分成一个固定区和若干个覆盖区。将经常活跃的部分放在固定区,...
  • 包括:内存管理单元MMU的作用,虚拟内存与物理内存之间的映射方式,页表的概念,高速缓存(Cache)的作用,物理内存与高速缓存之间的映射关系等。当然,想要深入了解,本文并不适合,本文只是从原理上,讲述以上几者...
  • Java内存管理

    千次阅读 2016-06-06 20:28:53
    而且了解了Java的内存管理,有助于优化JVM,从而使得自己的应用获得最佳的性能体验。所以还等什么,赶紧跟着我来一起学习这方面的知识吧~ Java内存管理分为两个方面:内存分配和垃圾回收,下面我们一一的来看一下。 ...
  • 存储管理功能

    万次阅读 2017-05-29 08:57:02
    存储管理功能 存储分配 存储共享 存储保护 存储扩充 地址映射 内存资源管理 内存分区 内存分配 静态等长分区的分配 动态异长分区的去配 紧凑 小结 存储管理功能 ...
  • 操作系统-内存管理

    万次阅读 多人点赞 2019-06-06 09:20:53
    有何作用1.1.2 进程运行的原理-指令1.1.3 逻辑地址VS物理地址1.1.4 进程运行的基本原理(从写程序到程序运行)1.1.5 装入内存的三种方式1.1.5 链接的三种方式1.1.6 总结1.2 内存管理的概念1.2.1 内存空间的分配与回收...
  • Linux内存管理机制(最透彻的一篇)

    万次阅读 多人点赞 2018-08-05 14:10:09
    摘要:本章首先以应用程序开发者的角度审视Linux的进程内存管理,在此基础上逐步深入到内核中讨论系统物理内存管理和内核内存的使用方法。力求从外到内、水到渠成地引导网友分析Linux的内存管理与使用。在本章最后,...
  • unity 内存管理

    千次阅读 2018-08-17 14:19:42
    转载至以下文章: https://onevcat.com/2012/11/memory-in-unity3d/ Unity 3D中的内存管理 https://docs.unity3d.com/Manual/iphone-playerSizeOptimization.html iOS stripping level(官网) ...
  • Linux内存管理(最透彻的一篇)

    万次阅读 多人点赞 2019-05-16 14:27:22
    【转】Linux内存管理(最透彻的一篇) 摘要:本章首先以应用程序开发者的角度审视Linux的进程内存管理,在此基础上逐步深入到内核中讨论系统物理内存管理和内核内存的使用方法。力求从外到内、水到渠成地引导网友...
  • Linux内存描述之内存页面page--Linux内存管理(四)

    万次阅读 多人点赞 2016-08-31 14:18:44
    日期 内核版本 架构 作者 GitHub CSDN 2016-08-31 ... Linux内存管理 1 前景回顾1.1 UMA和NUMA两种模型共享存储型多处理机有两种模型 均匀存储器存取(Uniform-Memory-Access,简称UMA)模型 非均匀存储器
  • 存储管理-存储管理功能

    千次阅读 2019-11-20 15:32:00
    存储管理-存储管理功能 存储器为什么比较重要? 存储器是计算机系统的重要资源之一。任何程序和数据以及各种控制用的数据结构都必须占用一定的存储空间,因此,存储管理直接影响系统性能。 存储器的组成 内存:存由...
  • 操作系统——内存分配管理

    千次阅读 2019-08-29 15:39:51
    1. 连续分配 1.1 单一连续分配 1.2 固定分区分配 1.3 动态分区分配 2. 非连续分配 2.1 基本分页存储管理方式 2.2 基本分段存储管理方式 2.3 段页式存储管理方式
  • 内存管理:页式虚拟内存管理

    千次阅读 2019-12-17 21:00:38
    页式存储管理——虚拟内存——缺页中断,页面替换算法 开章明意: 创建一个进程(创建进程是在磁盘中),进程以字节为单位编号,然后再进程分为许多页(每页4KB),内存中有对应的页框(设定同页)。通过页表(记录...
  • linux内存管理原理深入理解段式页式

    万次阅读 多人点赞 2017-07-20 08:52:39
    前一段时间看了《深入理解Linux内核》对其中的内存管理部分花了不少时间,但是还是有很多问题不是很清楚,最近又花了一些时间复习了一下,在这里记录下自己的理解和对Linux中内存管理的一些看法和认识。  我比较...
  • javascript中的内存管理

    千次阅读 2021-03-01 19:52:50
    在c语言中,我们需要手动分配和释放对象的内存,但是在java中,所有的内存管理都交给了java虚拟机,程序员不需要在手动进程内存的分配和释放,大大的减少了程序编写的难度。 同样的,在javascript中,内存管理也是...
  • C++内存管理(特详细)

    千次阅读 多人点赞 2019-06-02 11:28:30
    为了更好的进行学习,因此写在自己的...内存管理是C++最令人切齿痛恨的问题,也是C++最有争议的问题,C++高手从中获得了更好的性能,更大的自由,C++菜鸟的收获则是一遍一遍的检查代码和对C++的痛恨,但内存管理在C...
  • 日期 内核版本 架构 作者 GitHub ... Linux内存管理内存管理的上下文中, 初始化(initialization)可以有多种含义. 在许多CPU上, 必须显式设置适用于Linux内核的内存模型. 例如在x86_32上需要切换到
  • 日期 内核版本 架构 作者 GitHub ... Linux内存管理内存管理的上下文中, 初始化(initialization)可以有多种含义. 在许多CPU上, 必须显式设置适用于Linux内核的内存模型. 例如在x86_32上需要切换到
  • C++-内存管理

    千次阅读 多人点赞 2019-06-18 11:05:24
    **通过学习,这不是开玩笑,在我所学习的语言中,对内存的使用有如此的执着的“较真”也就是C++了。 因为性能的缘故,一个内存不合理的分配,都可能在日后成为一个隐患,成为一个令人头疼的BUG。所...
  • Java内存管理-内存分配与回收

    千次阅读 2017-12-29 17:48:00
    Java内存管理-内存分配与回收
  • 内存寻址 、硬件中的分段与分页 、Linux内存管理 页与内存管理区 、kmalloc()和vmalloc()
  • JVM的内存管理

    千次阅读 2018-11-19 16:02:03
    一:JVM内存模型图示 图1 图2 上面两个图都展示了虚拟机内存管理模式,整个运行时数据区又分为不同的内存区域,不同区域承担不...
  • Spark2.1 内存管理详解

    千次阅读 2018-12-11 14:16:23
    由于 Driver 的内存管理相对来说较为简单,本文主要对 Executor 的内存管理进行分析,下文中的 Spark 内存均特指 Executor 的内存。 1. 堆内和堆外内存规划 作为一个 JVM 进程,Executor 的内存管理建立在 JVM...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 553,445
精华内容 221,378
关键字:

内存管理的基本功能