操作系统面试常考知识点:虚拟内存45问
虚拟技术把一个物理实体转换成多个逻辑实体。主要分为两种:时分复用技术和空分复用技术
多进程和多线程:多个进程能在同一个处理器上并发执行使用了时分复用技术,让每个进程轮流占用处理器,每次只执行一个时间片并快速切换。虚拟内存使用了空分复用技术,它将物理内存抽象为地址空间,每个进程都有各自的地址空间。地址空间的页被映射到物理内存,地址空间的页并不需要全部在物理内存中,当使用到一个没有在物理内存的页时,执行页面置换算法,将该页置换到内存中。虚拟内存的目的是为了让物理内存扩充成更大的逻辑内存,从而使程序获得更多的可用内存。
页表:
为了更好的管理内存,操作系统将内存抽象成地址空间,每个程序拥有自己的地址空间,这个地址空间被分割成多个块,每一块称为一页。这些页被映射到物理内存,但不需要映射到连续的物理内存,也不需要所有的页都必须在物理内存中。当程序引用到不在物理内存中的页时,由硬件执行必要的映射,将缺失的部分装入物理内存并重新执行失败的指令。操作系统如何管理内存:
物理内存:物理内存有四个层次,分别是寄存器、高速缓存、主存、磁盘。
寄存器:速度最快、量少、价格贵。高速缓存:次之。主存:再次之。磁盘:速度最慢、量多、价格便宜。操作系统会对物理内存进行管理,有一个部分称为内存管理器(memory manager),它的主要工作是有效的管理内存,记录哪些内存是正在使用的,在进程需要时分配内存以及在进程完成时回收内存。虚拟内存:操作系统为每一个进程分配一个独立的地址空间,但是虚拟内存。虚拟内存与物理内存存在映射关系,通过页表寻址完成虚拟地址和物理地址的转换。
操作系统如何申请内存:
从操作系统角度来看,进程分配内存有两种方式,分别由两个系统调用完成:和内核态与用户态:内核态(系统态)与用户态是操作系统的两种运行级别。内核态拥有最高权限,可以访问所有系统指令;用户态则只能访问一部分指令。什么时候进入内核态:共有三种方式:a、系统调用。b、异常。c、设备中断。其中,系统调用是主动的,另外两种是被动的。为什么区分内核态与用户态:在CPU的所有指令中,有一些指令是非常危险的,如果错用,将导致整个系统崩溃。比如:清内存、设置时钟等。所以区分内核态与用户态主要是出于安全的考虑。外中断是由CPU执行指令以外的事件引起,如I/O完成中断,表示设备输入/输出处理已经完成,处理器能够发送下一个输入/输出请求。此外还有时钟中断、控制台中断等。异常是由CPU执行指令内部事件引起的,如非法操作码、地址越界、算术溢出。中断
中断是由硬件设备产生的,而它们从物理上说就是电信号,之后,它们通过中断控制器发送给CPU,接着CPU判断收到的中断来自于哪个硬件设备(这定义在内核中),最后,由CPU发送给内核,由内核处理中断。异常
异常是由 CPU 产生的,同时,它会发送给内核,要求内核处理这些异常。如:CPU处理程序的时候一旦程序不在内存中,会产生缺页异常;当运行除法程序时,当除数为0时,又会产生除0异常。相同点
最后都是由CPU发送给内核,由内核去处理不同点
产生源不相同,异常是由CPU产生的,而中断是由硬件设备产生的内核需要根据是异常还是中断调用不同的处理程序中断不是时钟同步的,这意味着中断可能随时到来;异常由于是CPU产生的,所以它是时钟同步的当处理中断时,处于中断上下文中;处理异常时,处于进程上下文中页表是虚拟内存的概念。操作系统虚拟内存到物理内存的映射表,就被称为页表。原因:不可能每一个虚拟内存的 Byte 都对应到物理内存的地址。因为这张表将大到真正的物理地址也放不下,于是操作系统引入了页(Page)的概念。进行分页,这样可以减小虚拟内存页对应物理内存页的映射表大小。缺页异常:malloc和mmap函数在分配内存时只是建立了进程虚拟地址空间,并没有分配虚拟内存对应的物理内存。当进程访问这些没有建立映射关系的虚拟内存时,处理器自动触发一个缺页异常,引发缺页中断。缺页中断:缺页异常后将产生一个缺页中断,此时操作系统会根据页表中的外存地址在外存中找到所缺的一页,将其调入内存。在进行动态内存分配时,例如malloc()函数或者其他高级语言中的new关键字,操作系统会在硬盘中创建或申请一段虚拟内存空间,并更新到页表(分配一个页表条目(PTE),使该PTE指向硬盘上这个新创建的虚拟页),通过PTE建立虚拟页和物理页的映射关系。页表:是一个存放在物理内存中的数据结构,它记录了虚拟页与物理页的映射关系快表,又称联想寄存器(TLB) ,是一种访问速度比内存快很多的高速缓冲存储器,用来存放当前访问的若干页表项,以加速地址变换的过程。与此对应,内存中的页表常称为慢表。相关视频推荐
庞杂的内存问题,如何理出自己的思路出来,让你开发与面试双丰收
6道经典的linux操作系统面试题,助你了解操作系统底层原理
90分钟搞懂linux内存架构,numa的优势,slab的实现,vmalloc的原理
免费学习地址:c/c++ linux服务器开发/后台架构师
需要C/C++ Linux服务器架构师学习资料加qun812855908获取(资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等),免费分享
CPU给出逻辑地址,由某个硬件算得页号、页内偏移量,将页号与快表中的所有页号进行比较。如果找到匹配的页号,说明要访问的页表项在快表中有副本,则直接从中取出该页对应的内存块号,再将内存块号和页内偏移量拼接形成物理地址,最后,访问该物理地址对应的内存单元。因此,若快表命中,则访问某个逻辑地址仅序一次即可。如果没有找到匹配的页号,则需要访问内存中的页表,找到对应页表项,得到页面存放的内存块号,再将内存块号与页内偏移量拼接成物理地址,最后,访问该物理地址对应的内存单元,因此,若快表未命中,则访问某个逻辑地址需要两次访存。(注意,在找到快表后,应同时将其存入快表,以便后面可能再次访问,若快表已满,则必须按照一定的算法对旧的页表项进行替换由于查询快表的速度比查询页表的速度快很多,因此只要快表命中,就可以节省很多时间。一般命中率在90%以上。无快表地址变换机构
①算页号、页内偏移量 ②检查页号合法性 ③查页表,找到页面存放的内存块号 ④根据内存块号与页内偏移量得到物理地址 ⑤访问目标内存单元 访问一个逻辑地址的访存次数:两次访存具有快表的地址变换机构
①算页号、页内偏移量 ②检查页号合法性 ③查快表。若命中,即可知道页面存放的内存块号,可直接进行⑤;若未命中则进行④ ④查页表,找到页面存放的内存块号,并且将页表项复制到快表中 ⑤根据内存块号与页内偏移量得到物理地址 ⑥访问目标内存单元 访问一个逻辑地址的访存次数:快表命中,只需一次访存 快表未命中,需要两次访存最佳置换法(OPT)
最佳置换算法可以保证最低的缺页率,但实际上,只有在进程执行的过程中才能知道接下来会访问到的是哪个页面。操作系统无法提前预判页面访问序列。因此,最佳置换算法是无法实现的。最佳置换算法(OPT,Optimal) :每次选择淘汰的页面将是以后永不使用,或者在最长时间内不再被访问的页面,这样可以保证最低的缺页率。 先进先出置换算法(FIFO)
先进先出置换算法(FIFO) :每次选择淘汰的页面是最早进入内存的页面。实现方法:把调入内存的页面根据调入的先后顺序排成一个队列,需要换出页面时选择队头页面队列的最大长度取决于系统为进程分配了多少个内存块。 只有FIFO算法会产生Belady异常,而LRU和OPT算法永远不会出现Belady异常。另外,FIFO算法虽然实现简单,但是该算法与进程实际运行时的规律不适应,因为先进入的页面也有可能最经常被访问。因此,算法性能差FIFO的性能较差,因为较早调入的页往往是经常被访问的页,这些页在FIFO算法下被反复调入和调出,并且有Belady现象。所谓Belady现象是指:采用FIFO算法时,如果对—个进程未分配它所要求的全部页面,有时就会出现分配的页面数增多但缺页率反而提高的异常现象。最近最久未使用置换算法(LRU)
最近最久未使用置换算法(LRU,least recently used) :每次淘汰的页面是最近最久未使用的页面 实现方法:赋予每个页面对应的页表项中,用访问字段记录该页面自.上次被访问以来所经历的时间t(该算法的实现需要专门的硬件支持,虽然算法性能好,但是实现困难,开销大)。当需要淘汰一个页面时,选择现有页面中t值最大的,即最近最久未使用的页面。LRU性能较好,但需要寄存器和栈的硬件支持。LRU是堆栈类算法,理论上可以证明,堆栈类算法不可能出现Belady异常。时钟置换算法(CLOCK)
简单的CLOCK算法实现方法:为每个页面设置一个访问位,再将内存中的页面都通过链接指针链接成一个循环队列。当某页被访问时,其访问位置为1。当需要淘汰-一个页面时,只需检查页的访问位。如果是0,就选择该页换出;如果是1,则将它置为0,暂不换出,继续检查下一个页面,若第- - ~轮扫描中所有页面都是1,则将这些页面的访问位依次置为0后,再进行第二轮扫描(第二轮扫描中一定会有访问位为0的页面,因此简单的CLOCK算法选择–个淘汰页面最多会经过两轮扫描)时钟置换算法是一种性能和开销较均衡的算法,又称CLOCK算法,或最近未用算法(NRU,Not Recently Used)最佳置换算法性性能最好,但无法实现;先进先出置换算法实现简单,但算法性能差;最近最久未使用置换算法性能好,是最接近OPT(最佳置换算法)性能的,但是实现起来需要专门的硬件支持,算法开销大。所以操作系统的设计者尝试了很多算法,试图用比较小的开销接近LRU的性能,这类算法都是CLOCK算法的变体,因为算法要循环扫描缓冲区像时钟一样转动。所以叫clock算法。最近最少未被使用(LFU)
LFU是最近最少未被使用。也就是说当页面满时,需要进行页面置换的时候,所采取的措施是在缓存队列中找到最近使用次数最少的页面,将其剔除出去。将新的页面加载到页面缓存队列中。也就是说在LFU中,需要记录每个页面被访问的次数。LRU算法:LRU算法用于缓存淘汰。思路是将缓存中最近最少使用的对象删除掉实现方式:利用链表和hashmap。当需要插入新的数据项的时候,如果新数据项在链表中存在(一般称为命中),则把该节点移到链表头部,如果不存在,则新建一个节点,放到链表头部,若缓存满了,则把链表最后一个节点删除即可。在访问数据的时候,如果数据项在链表中存在,则把该节点移到链表头部,否则返回-1。这样一来在链表尾部的节点就是最近最久未访问的数据项。虚拟内存分配:
用户空间:
代码段.text:存放程序执行代码的一块内存区域。只读,代码段的头部还会包含一些只读的常数变量。数据段.data:存放程序中已初始化的全局变量和静态变量的一块内存区域。BSS 段.bss:存放程序中未初始化的全局变量和静态变量的一块内存区域。可执行程序在运行时又会多出两个区域:堆区和栈区。堆区:动态申请内存用。堆从低地址向高地址增长。栈区:存储局部变量、函数参数值。栈从高地址向低地址增长。是一块连续的空间。最后还有一个共享区,位于堆和栈之间。
内核空间:DMA区、常规区、高位区。
什么时候进入内核态:共有三种方式:a、系统调用。b、异常。c、设备中断。其中,系统调用是主动的,另外两种是被动的。
物理内存:物理内存有四个层次,分别是寄存器、高速缓存、主存、磁盘。寄存器:速度最快、量少、价格贵。高速缓存:次之。主存:再次之。磁盘:速度最慢、量多、价格便宜。操作系统会对物理内存进行管理,有一个部分称为内存管理器(memory manager),它的主要工作是有效的管理内存,记录哪些内存是正在使用的,在进程需要时分配内存以及在进程完成时回收内存。虚拟内存:操作系统为每一个进程分配一个独立的地址空间,但是虚拟内存。虚拟内存与物理内存存在映射关系,通过页表寻址完成虚拟地址和物理地址的转换。为什么要用虚拟内存:因为早期的内存分配方法存在以下问题:进程地址空间不隔离。会导致数据被随意修改。内存使用效率低。程序运行的地址不确定。操作系统随机为进程分配内存空间,所以程序运行的地址是不确定的。使用虚拟内存的好处:扩大地址空间。每个进程独占一个4G空间,虽然真实物理内存没那么多。内存保护:防止不同进程对物理内存的争夺和践踏,可以对特定内存地址提供写保护,防止恶意篡改。可以实现内存共享,方便进程通信。可以避免内存碎片,虽然物理内存可能不连续,但映射到虚拟内存上可以连续。使用虚拟内存的缺点:虚拟内存需要额外构建数据结构,占用空间。虚拟地址到物理地址的转换,增加了执行时间。页面换入换出耗时。一页如果只有一部分数据,浪费内存。操作系统为每一个进程维护了一个从虚拟地址到物理地址的映射关系的数据结构,叫页表。页表中的每一项都记录了这个页的基地址。
三级页表转换方法:(两步)
逻辑地址转线性地址:段起始地址+段内偏移地址=线性地址线性地址转物理地址:页目录地址 + 页目录索引 = 页表地址页表地址 + 页表索引 = 页地址页地址 + 页内偏移 = 物理地址每一个32位的线性地址被划分为三部分:页目录索引(DIRECTORY,10位)、页表索引(TABLE,10位)、页内偏移(OFFSET,12位)从cr3中取出进程的页目录地址(操作系统调用进程时,这个地址被装入寄存器中)
按照以上两步法,就完成了一个三级页表从虚拟地址到物理地址的转换。
堆栈溢出就是不顾堆栈中分配的局部数据块大小,向该数据块写入了过多的数据,导致数据越界。常指调用堆栈溢出,本质上一种数据结构的满溢情况。堆栈溢出可以理解为两个方面:堆溢出和栈溢出。堆溢出:比如不断的new 一个对象,一直创建新的对象,而不进行释放,最终导致内存不足。将会报错:OutOfMemory Error。栈溢出:一次函数调用中,栈中将被依次压入:参数,返回地址等,而方法如果递归比较深或进去死循环,就会导致栈溢出。将会报错:StackOverflflow Error。malloc底层实现:当开辟的空间小于 128K 时,调用 brk()函数;当开辟的空间大于 128K 时,调用mmap()。malloc采用的是内存池的管理方式,以减少内存碎片。先申请大块内存作为堆区,然后将堆区分为多个内存块。当用户申请内存时,直接从堆区分配一块合适的空闲快。采用隐式链表将所有空闲块,每一个空闲块记录了一个未分配的、连续的内存地址。从操作系统层面上看,malloc是通过两个系统调用来实现的:brk和mmapbrk是将进程数据段(.data)的最高地址指针向高处移动,这一步可以扩大进程在运行时的堆大小mmap是在进程的虚拟地址空间中寻找一块空闲的虚拟内存,这一步可以获得一块可以操作的堆内存。通常,分配的内存小于128k时,使用brk调用来获得虚拟内存,大于128k时就使用mmap来获得虚拟内存。进程先通过这两个系统调用获取或者扩大进程的虚拟内存,获得相应的虚拟地址,在访问这些虚拟地址的时候,通过缺页中断,让内核分配相应的物理内存,这样内存分配才算完成。原理:mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用read, write等系统调用函数。相反,内核空间对这段区域的修改也直接反映用户空间,从而可以实现不同进程间的文件共享。如下图:使用场景:
对同一块区域频繁读写操作;可用于实现用户空间和内核空间的高效交互可提供进程间共享内存及相互通信可实现高效的大规模数据传输。
如上图,从高地址到低地址,一个程序由命令行参数和环境变量、栈、文件映射区、堆、bss段、数据段、代码段组成。
命令行参数和环境变量栈区:存储局部变量、函数参数值。栈从高地址向低地址增长。是一块连续的空间。文件映射区,位于堆和栈之间。堆区:动态申请内存用。堆从低地址向高地址增长。bss 段:存放程序中未初始化的全局变量和静态变量的一块内存区域。数据段:存放程序中已初始化的全局变量和静态变量的一块内存区域。代码段:存放程序执行代码的一块内存区域。只读,代码段的头部还会包含一些只读的常数变量。正常情况下是不可以的。原因是计算机使用二进制,每位数只有0或1两个状态,32位正好是2的32次方,正好是4G,所以大于4G就没办法表示了,而在32位的系统中,因其它原因还需要占用一部分空间,所以内存只能识别3G多。要使用4G以上就只能换64位的操作系统了。但是使用 PAE 技术就可以实现 32位系统能访问4GB以上的内存。Physical Address Extension(PAE)技术最初是为了弥补32位地址在PC服务器应用上的不足而推出的。我们知道,传统的IA32架构只有32位地址总线,只能让系统容纳不超过4GB的内存,这么大的内存,对于普通的桌面应用应该说是足够用了。可是,对于服务器应用来说,还是显得不足,因为服务器上可能承载了很多同时运行的应用。PAE技术将地址扩展到了36位,这样,系统就能够容纳2^36=64GB的内存。操作系统负责内存空间的分配和回收操作系统需要提供某种技术从逻辑上对内存空间进行扩充操作系统需要提供地址转换功能,负责程序的逻辑地址和物理地址的转换操作系统需要提供内存保护功能,保证各进程在各自存储空间内运行,互不干扰。① 首次适应算法
算法思想:每次都从低地址开始查找,找到第 1 个能满足大小的空闲分区。如何实现:空闲分区以地址递增的次序排列。每次分配内存时顺序查找空闲分区链(或空闲分[表),找到大小能满足要求的第一个空闲分区。② 最佳适应算法
算法思想:由于动态分区分配是一种连续分配方式,为各进程分配的空间必须是连续的一整片区域。因此为了保证当“大进程”到来时能有连续的大片空间,可以尽可能多地留下大片的空闲区,即,优先使用更小的空闲区。如何实现:空闲分区按容量递增次序链接。每次分配内存时顺序查找空闲分区链(或空闲分区表),找到大小能满足要求的第 1 个空闲分区。③ 最坏适应算法(最大适应算法(Largest Fit))
算法思想:为了解决最佳适应算法的问题—即留下太多难以利用的小碎片,可以在每次分配时优先使用最大的连续空闲区,这样分配后剩余的空闲区就不会太小,更方便使用。如何实现:空闲分区按容量递减次序链接。每次分配内存时顺序查找空闲分区链(或空闲分区表),找到大小能满足要求的第一个空闲分区。④ 邻近适应算法
算法思想:首次适应算法每次都从链头开始查找的。这可能会导致低地址部分出现很多小的空闲分区,而每次分配查找时,都要经过这些分区,因此也增加了查找的开销。如果每次都从上次查找结束的位置开始检索,就能解决上述问题。如何实现:空闲分区以地址递增的顺序排列(可排成-一个循环链表)。每次分配内存时从上次查找结束的位置开始查找空闲分区链(或空闲分区表),找到大小能满足要求的第一个空闲分区。总结
首次适应不仅最简单,通常也是最好最快,不过首次适应算法会使得内存低地址部分出现很多小的空闲分区,而每次查找都要经过这些分区,因此也增加了查找的开销。邻近算法试图解决这个问题,但实际上,它常常会导致在内存的末尾分配空间分裂成小的碎片,它通常比首次适应算法结果要差。最佳导致大量碎片,最坏导致没有大的空间。经过实验,首次适应比最佳适应要好,它们都比最坏好。读写一个磁盘块的时间的影响因素有:
旋转时间(主轴转动盘面,使得磁头移动到适当的扇区上)寻道时间(制动手臂移动,使得磁头移动到适当的磁道上)其中,寻道时间最长,因此磁盘调度的主要目标是使磁盘的平均寻道时间最短。
先来先服务优点是公平和简单。缺点也很明显,因为未对寻道做任何优化,使平均寻道时间可能较长。按照磁盘请求的顺序进行调度。最短寻道时间优先优先调度与当前磁头所在磁道距离最近的磁道。虽然平均寻道时间比较低,但是不够公平。如果新到达的磁道请求总是比一个在等待的磁道请求近,那么在等待的磁道请求会一直等待下去,也就是出现饥饿现象。具体来说,两端的磁道请求更容易出现饥饿现象。电梯扫描算法电梯算法(扫描算法)和电梯的运行过程类似,总是按一个方向来进行磁盘调度,直到该方向上没有未完成的磁盘请求,然后改变方向。因为考虑了移动方向,因此所有的磁盘请求都会被满足,解决了 SSTF 的饥饿问题。电梯总是保持一个方向运行,直到该方向没有请求为止,然后改变运行方向。交换空间
Linux 中的交换空间(Swap space)在物理内存(RAM)被充满时被使用。如果系统需要更多的内存资源,而物理内存已经充满,内存中不活跃的页就会被移到交换空间去。虽然交换空间可以为带有少量内存的机器提供帮助,但是这种方法不应该被当做是对内存的取代。交换空间位于硬盘驱动器上,它比进入物理内存要慢。交换空间可以是一个专用的交换分区(推荐的方法),交换文件,或两者的组合。交换空间的总大小应该相当于你的计算机内存的两倍和 32 MB这两个值中较大的一个,但是它不能超过 2048MB(2 GB)。虚拟内存
虚拟内存是文件数据交叉链接的活动文件。是WINDOWS目录下的一个"WIN386.SWP"文件,这个文件会不断地扩大和自动缩小。就速度方面而言,CPU的L1和L2缓存速度最快,内存次之,硬盘再次之。但是虚拟内存使用的是硬盘的空间,为什么我们要使用速度最慢的硬盘来做 为虚拟内存呢?因为电脑中所有运行的程序都需要经过内存来执行,如果执行的程序很大或很多,就会导致我们只有可怜的256M/512M内存消耗殆尽。而硬盘空间动辄几十G上百G,为了解决这个问题,Windows中运用了虚拟内存技术,即拿出一部分硬盘空间来充当内存使用。由于程序运行时并非任何时候都要访问程序及数据的各个部分(尤其是大程序),因此可以把用户空间分成为一个固定区和若干个覆盖区。将经常活跃的部分放在固定区,其余部分按照调用关系分段,首先将那些即将要访问的段放入覆盖区,其他段放在外存中,在需要调用前,系统将其调入覆盖区,替换覆盖区中原有的段。覆盖技术的特点:是打破了必须将一个进程的全部信息装入内存后才能运行的限制,但当同时运行程序的代码量大于主存时仍不能运行,再而,大家要注意到,内存中能够更新的地方只有覆盖区的段,不在覆盖区的段会常驻内存。交换(对换)技术的设计思想:内存空间紧张时,系统将内存中某些进程暂时换出外存,把外存中某些已具备运行条件的进程换入内存(进程在内存与磁盘间动态调度)换入:把准备好竞争CPU运行的程序从辅存移到内存。换出:把处于等待状态(或CPU调度原则下被剥夺运行权力)的程序从内存移到辅存,把内存空间腾出来。内存交换通常在许多进程运行且内存吃紧时进行,而系统负荷降低就暂停。例如:在发现许多进程运行时经常发生缺页,就说明内存紧张,此时可以换出一些进程;如果缺页率明显下降,就可以暂停换出。主要分为时间局部性和空间局部性。
时间局部性:如果执行了程序中的某条指令,那么不久后这条指令很有可能再次执行;如果某个数据被访问过,不久之后该数据很可能再次被访问。(因为程序中存在大量的循环)空间局部性:一旦程序访问了某个存储单元,在不久之后,其附近的存储单元也很有可能被访问。(因为很多数据在内存中都是连续存放的,并且程序的指令也是顺序地在内存中存放的)刚刚换出的页面马上又要换入内存,刚刚换入的页面马上又要换出外存,这种频繁的页面调度行为称为抖动,或颠簸。产生抖动的主要原因是进程频繁访问的页面数目高于可用的物理块数(分配给进程的物理块不够)为进程分配的物理块太少,会使进程发生抖动现象。为进程分配的物理块太多,又会降低系统整体的并发度,降低某些资源的利用率为了研究为应该为每个进程分配多少个物理块,Denning 提出了进程工作集” 的概念从两方面来考虑:
分配和释放,堆在分配和释放时都要调用函数(malloc,free),比如分配时会到堆空间去寻找足够大小的空间(因为多次分配释放后会造成内存碎片),这些都会花费一定的时间,具体可以看看malloc和free的源代码,函数做了很多额外的工作,而栈却不需要这些。访问时间,访问堆的一个具体单元,需要两次访问内存,第一次得取得指针,第二次才是真正的数据,而栈只需访问一次。另外,堆的内容被操作系统交换到外存的概率比栈大,栈一般是不会被交换出去的。内存分配方式
从静态存储区域分配:内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。在栈上创建:在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。从堆上分配,亦称动态内存分配:程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。内存分配未成功,却使用了它。常用解决办法是,在使用内存之前检查指针是否为NULL。如果指针p是函数的参数内存分配虽然成功,但是尚未初始化就引用它。内存分配成功并且已经初始化,但操作越过了内存的边界忘记了释放内存,造成内存泄露。释放了内存却继续使用它。常见于以下有三种情况:程序中的对象调用关系过于复杂,实在难以搞清楚某个对象究竟是否已经释放了内存,此时应该重新设计数据结构,从根本上解决对象管理的混乱局面。函数的return语句写错了,注意不要返回指向“栈内存”的“指针”或者“引用”,因为该内存在函数体结束时被自动销毁。使用free或delete释放了内存后,没有将指针设置为NULL。导致产生“野指针”。保存在磁盘中,也就是外存中。具有对换功能的操作系统中,通常把磁盘空间分为文件区和对换区两部分。文件区主要用于存放文件,主要追求存储空间的利用率,因此对文件区空间的管理采用离散分配方式;对换区空间只占磁盘空间的小部分,被换出的进程数据就存放在对换区。由于对换的速度直接影响到系统的整体速度,因此对换区空间的管理主要追求换入换出速度,因此通常对换区采用连续分配方式(学过文件管理章节后即可理解)。总之,对换区的I/O速度比文件区的更快。可优先换出阻塞进程;可换出优先级低的进程;为了防止优先级低的进程在被调入内存后很快又被换出,有的系统还会考虑进程在内存的驻留时间… (注意: PCB 会常驻内存,不会被换出外存)交换需要备份存储,通常是快速磁盘,它必须足够大,并且提供对这些内存映像的直接访问。为了有效使用CPU,需要每个进程的执行时间比交换时间长,而影响交换时间的主要是转移时间,转移时间与所交换的空间内存成正比。如果换出进程,比如确保该进程的内存空间成正比。交换空间通常作为磁盘的一整块,且独立于文件系统,因此使用就可能很快。交换通常在有许多进程运行且内存空间吃紧时开始启动,而系统负荷降低就暂停。普通交换使用不多,但交换的策略的某些变种在许多系统中(如UNIX系统)仍然发挥作用。处理器使用基于对缓存加锁或总线加锁的方式来实现多处理器之间的原子操作。首先处理器会自动保证基本的内存操作的原子性。处理器保证从系统内存中读取或者写入一个字节是原子的,意思是当一个处理器读取一个字节时,其他处理器不能访问这个字节的内存地址。Pentium 6和最新的处理器能自动保证单处理器对同一个缓存行里进行16/32/64位的操作是原子的,但是复杂的内存操作处理器是不能自动保证其原子性的,比如跨总线宽度、跨多个缓存行和跨页表的访问。但是,处理器提供总线锁定和缓存锁定两个机制来保证复杂内存操作的原子性。共享是指系统中的资源可以被多个并发进程共同使用。有两种共享方式:互斥共享和同时共享。互斥共享的资源称为临界资源,例如打印机等,在同一时刻只允许一个进程访问,需要用同步机制来实现互斥访问。内碎片:分配给某些进程的内存区域中有些部分没用上,常见于固定分配方式内存总量相同,100M固定分配,将100M分割成10块,每块10M,一个程序需要45M,那么需要分配5块,第五块只用了5M,剩下的5M就是内部碎片;分段式分配,按需分配,一个程序需要45M,就给分片45MB,剩下的55M供其它程序使用,不存在内部碎片。外碎片:内存中某些空闲区因为比较小,而难以利用上,一般出现在内存动态分配方式中。分段式分配:内存总量相同,100M,比如,内存分配依次5M,15M,50M,25M,程序运行一段时间之后,5M,15M的程序运行完毕,释放内存,其他程序还在运行,再次分配一个10M的内存供其它程序使用,只能从头开始分片,这样,就会存在10M+5M的外部碎片对于外部碎片,通过紧凑技术消除,就是操作系统不时地对进程进行移动和整理。但是这需要动态重定位寄存器地支持,且相对费时。紧凑地过程实际上类似于Windows系统中地磁盘整理程序,只不过后者是对外存空间地紧凑解决外部内存碎片的问题就是内存交换。存储器:内存控制器:南桥北桥运算器:CPU输入设备:键盘输出设备:显示器、网卡进程地址空间(地址空间)虚拟存储器为每个进程提供了独占系统地址空间的假象。尽管每个进程地址空间内容不尽相同,但是它们都有相似的结构。X86 Linux进程的空间底部是保留给用户程序的,包括文本、数据、堆、栈等,其中文本区和数据区是通过存储区映射方式将磁盘中可执行文件的相应段映射到虚拟存储器地址空间中。一些敏感的地址需要注意一下,对于32位进程来说,代码段从0x08048000开始。从0xC0000000开始到0xFFFFFFFF是内核地址空间,通常情况下代码运行在用户态(使用0x00000000 ~ 0xC0000000的用户地址空间),当发生系统调用、进程切换等操作时CPU控制寄存器设置 模式位,进入内核模式,在该状态(超级用户模式)下进程可以访问全部存储区位置和执行全部指令。也就是说32位进程的地址空间都是4G,但用户态下只能访问低3G的地址空间,若要访问3G ~ 4G的地址空间则只有进入内核态才行。进程控制块(处理机)进程的调度实际就是内核选择相应的进程控制块,被选择的进程控制块中包含了一个进程基本的信息。上下文切换内核管理所有进程控制块,而进程控制块记录了进程全部状态信息。每一次进程调度就是依次上下文切换,所谓的上下文本质上就是当前运行状态,主要包括通用寄存器、浮点寄存器、程序计数器、用户栈和内核数据结构(页表、进程表、文件表)等。进程执行时刻,内核可以决定抢占当前进程并开始新的进程,这个过程由内核调度器完成,当调度器选择了某个进程时称为该进程被调度,该进程通过上下文切换来改变当前状态。一次完整的上下文切换通常是进程原先运行于用户态,之后因系统调用或时间片到切换到内核态执行内核指令,完成上下文切换后回到用户态,此时已经切换到进程B。小端模式:低的有效字节存储在低的存储器地址。小端一般为主机字节序;常用的X86结构是小端模式。很多的ARM,DSP都为小端模式。
大端模式:高的有效字节存储在低的存储器地址。大端为网络字节序;KEIL C51则为大端模式。
有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。
如何判断:我们可以根据联合体来判断系统是大端还是小端。因为联合体变量总是从低地址存储。
在进行网络通信时是否需要进行字节序转换?相同字节序的平台在进行网络通信时可以不进行字节序转换,但是跨平台进行网络数据通信时必须进行字节序转换。原因如下:网络协议规定接收到得第一个字节是高字节,存放到低地址,所以发送时会首先去低地址取数据的高字节。小端模式的多字节数据在存放时,低地址存放的是低字节,而被发送方网络协议函数发送时会首先去低地址取数据(想要取高字节,真正取得是低字节),接收方网络协议函数接收时会将接收到的第一个字节存放到低地址(想要接收高字节,真正接收的是低字节),所以最后双方都正确的收发了数据。而相同平台进行通信时,如果双方都进行转换最后虽然能够正确收发数据,但是所做的转换是没有意义的,造成资源的浪费。而不同平台进行通信时必须进行转换,不转换会造成错误的收发数据,字节序转换函数会根据当前平台的存储模式做出相应正确的转换,如果当前平台是大端,则直接返回不进行转换,如果当前平台是小端,会将接收到得网络字节序进行转换。网络字节序网络上传输的数据都是字节流,对于一个多字节数值,在进行网络传输的时候,先传递哪个字节?也就是说,当接收端收到第一个字节的时候,它将这个字节作为高位字节还是低位字节处理,是一个比较有意义的问题; UDP/TCP/IP协议规定:把接收到的第一个字节当作高位字节看待,这就要求发送端发送的第一个字节是高位字节;而在发送端发送数据时,发送的第一个字节是该数值在内存中的起始地址处对应的那个字节,也就是说,该数值在内存中的起始地址处对应的那个字节就是要发送的第一个高位字节(即:高位字节存放在低地址处);由此可见,多字节数值在发送之前,在内存中因该是以大端法存放的; 所以说,网络字节序是大端字节序; 比如,我们经过网络发送整型数值0x12345678时,在80X86平台中,它是以小端发存放的,在发送之前需要使用系统提供的字节序转换函数htonl()将其转换成大端法存放的数值;
上一篇:合肥市蜀山区:科学家任小学副校长
下一篇:上海松江区作业辅导班哪家好
最近更新教育教学
- 济南将碎片化经验总结提升,创新推出五项地方标准 让学前教育高质量发展有“标准”可
- 拓斯达:三季度实现扣非归母净利润同比增长27.39%,盈利能力持续提升
- “亚运薪火”与“宸星星火”同频共振 中学运动会迎来亚运冠军
- 多地清退编外人员,他们的“编外困局”:有人没资格报考所在岗位,有人因编外经历失去
- 民航局发布《活体动物航空运输工作指南》
- 合肥市淮河路第三小学教育集团映月校区:借数字应用于课堂 创智慧引领于教学
- 促进家校共育 巴蜀蓝湖郡小学开展家校共话成长系列活动
- 云南电网公司充分发挥公司律师四个作用助推企业高质量发展
- 汇聚邻里 共筑幸福丨合肥万科物业2023“朴里节”圆满落幕!
- 中拉跨越大洋高质量共建“一带一路”
- 广东报名自考有什么条件?
- 山东东营:文明宣讲进乡村 勤俭节约树新风
- 初中女生体测时突然心脏骤停……心肺复苏+AED“救了命”!
- 李刚,进京任职
- 1-9月海口港海关共受理“加工增值”试点扩区企业内销报关单404票 合计货值1.
- 重逢雁栖湖畔,国科大校友回家啦!
- 好水才能养好蟹
- 这种“鱼骨线”能变道吗?答案是……
- 今年上半年全球手机CIS传感器出货量20亿:同比下降14%
- 撑一支长蒿,向青草更青处漫溯
- 自考相对容易专业都有哪些?
- 远程“扶智”让优质教育资源“动”起来
- 黄喜灿:能被瓜迪奥拉称赞非常荣幸,新绰号可以向大家多宣传韩国
- AI赋能教育智变
- 同题观点