美文网首页iOS 笔记
iOS程序中的内存分为五个区

iOS程序中的内存分为五个区

作者: Dayon | 来源:发表于2018-05-21 18:11 被阅读2次

    关于RAM&ROM

    RAM与ROM就是具体的存储空间,统称为存储器。

    RAM(random access memory):运行内存,CPU可以直接访问,读写速度非常快,但是不能掉电存储。它又分为:

    动态DRAM,速度慢一点,需要定期的刷新(充电),我们常说的内存条就是指它,价格会稍低一点,手机中的运行内存也是指它。

    静态SRAM,速度快,我们常说的一级缓存,二级缓存就是指它,当然价格高一点。

    ROM(read only memory):存储性内存,可以掉电存储,例如SD卡、Flash(机械磁盘也可以简单的理解为ROM)。用的多的:NandFlash,还有NorFlash,现在用的已经比较少了(两者主要区别是前者空间大,便宜,后者可以直接运行程序,读取速度快)。

    由于RAM类型不具备掉电存储能力(即一停止供电数据全没了,从新上电后全是乱码,所以需要初始化),所以app程序一般存放于ROM中。RAM的访问速度要远高于ROM,价格也要高。

    RAM与ROM协同工作
    由于RAM不能掉电存储,所以我们的APP程序,刷机包,下载的文件等等,都是在ROM里面存储的。

    手机里面使用的ROM基本都是NandFlash,CPU是不能直接访问的,而是需要文件系统/驱动程序(嵌入式中的EMC)将其读到RAM里面,CPU才可以访问。另外,RAM的速度也比NandFlash快。

    内存分区

    说到内存分区,内存即指的是RAM。
    内存分为五个区:栈区(系统管理的地方)、堆区(程序员控制的地方)、静态区(全局区)、常量区、代码区。

    image.png

    1、栈区(stack): 由编译器自动分配并释放,存放函数的参数值,局部变量等。栈是系统数据结构,对应线程/进程是唯一的。

    优点:

    • 快速高效,缺点时有限制,数据不灵活。[先进后出]
    • 栈空间分静态分配 和动态分配两种。
    • 静态分配是编译器完成的,比如自动变量(auto)的分配。
    • 动态分配由alloca函数完成。
    • 栈的动态分配无需释放(是自动的),也就没有释放函数。
    • 为可移植的程序起见,栈的动态分配操作是不被鼓励的!

    2、堆区(heap) :由程序员分配和释放,如果程序员不释放,程序结束时,可能会由操作系统回收 ,比如在ios 中 alloc 都是存放在堆中。

    优点:

    • 灵活方便,数据适应面广泛,但是效率有一定降低。[顺序随意]
    • 堆是函数库内部数据结构,不一定唯一。
    • 不同堆分配的内存无法互相操作。
    • 堆空间的分配总是动态的
    • 虽然程序结束时所有的数据空间都会被释放回系统,但是精确的申请内存,释放内存匹配是良好程序的基本要素。

    3、全局区(静态区) (static): 全局变量和静态变量的存储是放在一起的,初始化的全局变量和静态变量存放在一块区域,未初始化的全局变量和静态变量在相邻的另一块区域,程序结束后有系统释放。

    注意:全局区又可分为未初始化全局区:
    .bss段和初始化全局区:data段。
    举例:int a;未初始化的。int a = 10;已初始化的。

    例子代码:

    int a = 10; 全局初始化区
    char *p; 全局未初始化区
    
     main{
       int b; 栈区
       char s[] = "abc" 栈
       char *p1; 栈 
       char *p2 = "123456";  123456\\\\0在常量区,p2在栈上。
       static int c =0; 全局(静态)初始化区 
    
       w1 = (char *)malloc(10); 
       w2 = (char *)malloc(20); 
       分配得来得10和20字节的区域就在堆区。 
     }
    

    4、文字常量区: 存放常量字符串,程序结束后由系统释放

    5、程序代码区: 存放函数的二进制代码

    总结:

    • 栈:由系统自动分配,速度较快,不会产生内存碎片 [先进后出]
    • 堆:是由alloc分配的内存,速度比较慢,而且容易产生内存碎片,不过用起来最方便

    打个比喻来说:

    • 使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。
    • 使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。

    程序运行举例(CPU RAM ROM之间协同)

    首先了解下:虚拟内存与物理内存。

    手机上的所有程序都是依托操作系统,运行在虚拟内存上的,每一个APP都会以为自己拥有所有的虚拟内存。比如一个手机,它是32位操作系统(一般也是32位总线),真实的物理内存为2G,那么他的寻址空间为4G(2的32次方),对于APP来说,它觉得自己拥有4G的内存,虽然这是不可能的(或者说同一时间是不可能的),但是,操作系统只要保证APP当时用到的地址空间有真实的物理地址对应就可以,APP也不需要知道那对应的2G真实物理内存具体在哪里。不要求4G的虚拟内存同一时间都有真实的物理内存相对应,当然那也是不可能的,因为只有2G物理内存。

    在下面的举例中,只考虑虚拟内存

    当我们点击手机屏幕APP的Icon启动一个APP(例如微信)时,操作系统会为微信开辟4G的虚拟内存空间(开辟真实的物理内存,对应一部分到4G的虚拟内存),操作系统会把存储在ROM里面微信的部分代码(受空间所限,不可能全部拷贝),拷贝到上一步开辟的4G内存空间的代码区,如上图,然后CPU就可以访问RAM来运行微信的程序了 。

    假设通过微信我们下载了一个100M的视频,那么会从服务器一点一点的下载到RAM,然后再从RAM写到ROM存储。这样才能保证,我们关掉微信并再次打开时视频还在。假设隔一段时间,我们要看视频,程序会将它从ROM读到RAM然后解码播放。


    CPU RAM ROM之间协同

    注意

    当一个app启动后,代码区,常量区,全局区地址已固定,因此指向这些区的指针不会为空而产生崩溃性的错误。而堆区和栈区是时时刻刻变化的(堆的创建销毁,栈的弹入弹出),所以当使用一个指针指向这两个区里面的内存时,一定要注意内存是否已经被释放,否则会产生程序崩溃(编程中很常见)

    相关文章

      网友评论

        本文标题:iOS程序中的内存分为五个区

        本文链接:https://www.haomeiwen.com/subject/tgljgxtx.html