概述

●我们电脑上运行的程序都是使用虚拟存储,跟物理内存根本不搭边

●既然虚拟内存是在磁盘上的,为什么它又运行这么好,并没有感觉卡顿?这要感谢程序的局部性!

●虚拟存储器的调度是一个操作系统必须做好的事情!不然程序就会慢的跟蜗牛一样。

垃圾收集器就是一个动态分配器,它自动释放这些程序不再需要的已分配的块。

●在64处理器的PC上获取一个变量的地址发现是:6个字节?比如i7的核64位,但是只能寻址48位,所以指针是6个字节。(一个指针所占内存取决于寻址位数)指针字节跟操作系统的位没有必然关系。

●由于虚拟存储器的存在使得程序链接和加载都很容易。比如程序的“代码段”,总是从虚拟地址0x08048000开始的

“写时拷贝”是一个非常重要的概念。

一个系统中的进程是与其他进程共享CPU和内存资源的,然而,如果太多的进程需要太多的存储器,那么他们中的一些就根本无法运行。存储器还很容易破坏。如果某个进程不小心写了另外一个进程的存储器,它就可能易某种完全跟程序逻辑无关的方式失败。为了更加有效地管理存储器并且少出错,现代系统提供了一种对内存的抽象概念,叫做虚拟存储器(VM).

作为程序员我们为什么要了解虚拟存储器呢。1)虚拟存储器是中心。虚拟存储编辑系统的所有层面。2),虚拟存储器是强大的。虚拟存储器给予应用程序强大的能力,可以创建和销毁存储器片(chunk)、将存储器片映射到磁盘文件的某个部分,以及其他进程共享存储器。3),虚拟存储器是危险的。每次应用程序引用一个变量、间接引用一个指针,或者调用一个类似与malloc的动态分配的函数,就会跟虚拟存储器打交道。

虚拟页和虚拟存储器是真实存放在磁盘上的,虚拟存储器它有几个功能:作为缓存的工具,作为管理存储器的工具,作为存储器保护的工具。

9.1物理和虚拟寻址

早期的计算机采用物理寻址(Physical Addressing),现代的计算机采用虚拟寻址(virtual addressing),将一个虚拟地址转换为物理地址的任务叫做地址翻译。地址翻译需要CPU硬件和操作系统之间的紧密合作。CPU芯片中有一个MMU的存储器管理单元Memory Management Unit)。如下图所示:

从上面两张图上发现,虚拟寻址只是CPU的一种技术

9.2地址空间

地址空间是一个非负数地址的有序集合:如果地址空间的整数是连续的,那么我们说它是一个线性地址空间。那么一个拥有虚拟寻址的CPU,也就会有一个虚拟地址空间。内存中的一个字节,就会有一个物理地址和一个虚拟地址。如果CPU有N个虚拟地址空间,那么该字节就有N个虚拟地址。

9.3虚拟存储器作为缓存的工具

概念上而言,虚拟存储器被组织为一个由“存放在磁盘上的N个连续字节大小的单元”组成的数组。磁盘上的内容被缓存到内存中,内存和磁盘之间采用块block格式传输。由于虚拟存储的技术早于高速缓存的技术,所以当时这种块被称之为页(page),也就是现在的说法。如下图:

上图展示了一个8个虚拟页的小型虚拟存储器。绿色的3个页表示已经缓存到内存了(参考内存中绿色的三个页)连个未分配和三个未缓存的。

由于内存的访问速度比磁盘快100000倍,所以如果内存不命中,那么代价将是非常高的(程序运行将非常慢),另外,读取磁盘某一个扇区第一个字节的开销比起读取整个扇区的字节慢100000倍。这两个条件决定了虚拟存储的页的大小最好是一个扇区或几个扇区。典型地是4KB-2MB。(一个扇区一般在512byte,4k==512x8)

还有,即便是有个很大的页,如果操作系统在替换页的操作处理不当,速度将会很慢。缺页是一种异常,名字就叫“缺页”,发生异常后,虚拟存储器加载磁盘(rom?)到内存(ram)并替换牺牲页。操作系统再次运行该指令,就不再缺页了。

当我们与多人了解了虚拟存储器的概念之后,我们的第一印象是:“它的效率应该很低下吧,因为如果不命中,那么代价将非常高。”我们也担心页面的调度破坏程序的性能。实际上,虚拟存储器运行的相当好,主要归功于程序局部性(locality).

尽管整个运行过程中程序引用的不同页面的总数可能超出物理存储器的总的大小,但是局部性原则保证了在任意时刻,程序将往往在一个较小的活动页面(active page)集合工作,这个集合叫做工作集。

tips 在Unix系统中使用getrusage函数来检测缺页的数量

9.4虚拟存储器作为存储器管理工具

实际上,操作系统为“每一个进程”提供了一个独立的页表,因而也就是一个独立的虚拟地址空间。展现形式就是:让人感觉这个程序正在完全是使用CPU和内存资源。如下图,多个虚拟叶面同事映射到同一个共享物理页面上(动态链接库或者叫共享库就是这个原理)。

进程独立的地址空间允许每个进程的存储器映像使用相同的基本格式,而不管代码和数据实际存放在物理存储器的地方。比如Linux系统上每个进程文本节总是从虚拟地址0x08048000初开始。总结起来说:虚拟存储器简化了链接、简化了加载、简化共享和简化存储器分配

9.5虚拟存储器作为存储器保护的工具

现代操作系统都严格限制普通应用程序访问自己的只读数据和别进程的数据,还有操作系统的内核部分。所以虚拟存储器可以在页的开始部分设置几个标志位用于标明这个进程是系统进程还是用户进程。如果某一天指令违反了这个条件,那么CPU就触发一个异常。Unix外壳一般将这种异常报告为“段错误segmentation fault

9.6地址翻译,有点儿专业。跟应用程序层面关系不大。

9.7案例研究:Intel Core i7/Linux存储器系统

在64位的mac电脑上打印一个变量的指针,结果指针是6个字节。这是因为i7的CPU只支持48位的虚拟地址,和52位的物理地址空间。虽然我的mac是i5的但是估计也是48位虚拟地址。其他内容是地址翻译,缺页异常。

Linux虚拟存储器区域:Linux将虚拟存储器组织成一些区域的集合。一个区域(area)就是已经存在着(已分配的)的虚拟存储器的连续片(chunk)

9.8存储器映射

有一个疑问:“电脑4G的内存,加载一个程序很慢,但是看看内存剩余量,还有剩余内存,不应该慢啊。如果升级到8G的内存,程序加载的快了。这是因为操作系统有一个叫做交换空间的东西,交换空间可能显示虚拟存储器的页数“。明白了,如果内存大,交换空间就大,程序加载就快。

概念:私有有的写时拷贝,理解这个概念很重要。用图来说明:

上图右部分说明了写时拷贝:进程1和2都共享内存中的一组页,但是进程2需要写最后一个页。那么启动写时拷贝,拷贝最后一页到内存其他地方。(内存中的页,可能不是连续的)。

fork函数直接在虚拟存储器上开辟一段,跟主进程一不一样的拷贝,那么,也就跟主进程指向同一个物理存储器。从上图左边部分中我们可以印证一下进程2可以看做是从进程1调用fork函数创建的。

execve是如何加载应用程序的。execve函数在当前进程中加载并运行a.out,用a.out程序有效的替换了当前程序。加载a.out时候需要以下几个步骤:

1)删除已存在的用户区域。

2)映射私有区域。为新的程序的文本、数据、bss、和栈区域创建新的区域结构。

3)映射共享区域。

4)设置程序技术器PC。使之指向文本区域的入口点。

9.9动态存储器分配malloc

动态分配,我自己的理解就是分配在虚拟存储器中的区域,这个区域可能已经在内存中了,也可能在磁盘上。

下面是真正的定义:动态存储器分配器,维护着一个进程的虚拟存储器区域,成为”堆“,对于每一个进程,操作系统内核维护着一个变量brk(break)指向堆的顶部。分配器有两种基本风格。

1)显式分配器:例如C和C++的malloc 和new 运算法。但是需要程序员收到free和delete处理。

2)隐式分配器:也叫做垃圾收集器,其自动释放未使用的已分配的块的过程叫做垃圾收集。例如:Java的垃圾回收机制。

动态存储分配器的要求和目标

●处理任意请求序列。

●立即响应请求。分配器必须立即响应分配请求。因此不允许分配器提高性能,从新排列或者缓冲请求。

●只是用堆。

●对齐块,比如8个字节的对齐。

●不修改已分配的块。不能压缩已分配的块。

目标

●1最大化吞吐率

●2最大化存储器的利用率。天真的程序员经常不正确的假设虚拟存储器是一个无限的资源,事实上,一个系统中被所有进程分配的虚拟存储器的全部数量是受磁盘上交换空间的数量限制的。

存储器碎片(这是一个很有意思的话题)。首先介绍内部碎片和外部碎片。如图:

外部碎片要比内部碎片处理复杂得多!分配器还要有其他功能:合并空闲的块,也是非常有意思的(原书使用19页的量,来描述分配器的原理和动作),聪明的程序员采用了很多种技巧来实现,参考p568页☆☆

9.10 垃圾收集(回收)

    垃圾收集器就是一个动态分配器,它自动释放这些程序不再需要的已分配的块。垃圾收集可以追溯到20世纪60年代早起在MIT开发的Lisp系统。他是诸如Java、ML、Perl和Mathematica等现代语言系统的一个重要的部分。
    垃圾回收的原理,如图。那些灰色的小圆点表示已经是垃圾了,需要清理。
    是用专业的词语是:上图是一张可达图,蓝色的块表示可达,灰色的块表示不可达(从任意根节点出发不可达)。

9.11程序中常见的与存储器有关的错误。

●间接引用坏指针

●读未初始化的存储器

●允许栈缓存去溢出

●假设指针和它们指向的对象是相同大小的

●造成错位

●引用指针,而不是它指向的对象

●误解指针运算

●应用不存在的变量

●应用空闲块中的数据

●引起存储器泄露

总结

虚拟存储器的三个重要功能:
第一,它在内存中自动缓存“最近使用的存放在磁盘上的”虚拟地址空间的内容。
第二,虚拟存储器简化了存储器的管理,简化链接和共享。
第三,虚拟存储器通过在每条页表条目中加入保护位从而简化了存储器保护。
 
原文:http://blog.csdn.net/hherima/article/details/8965892

3.6《深入理解计算机系统》笔记(四)虚拟存储器,malloc,垃圾回收【插图】的更多相关文章

  1. TIJ读书笔记06-终结清理和垃圾回收

    TIJ读书笔记06-终结清理和垃圾回收 finalize()方法 垃圾回收器如何工作 java的垃圾回收是由jvm来控制的.所以需要java程序员参与的部分不是很多. 但是在这里需要明白一点,java ...

  2. ☕【JVM技术指南】「JVM总结笔记」Java虚拟机垃圾回收认知和调优的"思南(司南)"【下部】

    承接上文 (完结撒花1-52系列)[JVM技术指南]「JVM总结笔记」Java虚拟机垃圾回收认知和调优的"思南(司南)"[上部] 并行收集器 并行收集器(也称为吞吐量收集器)是类似 ...

  3. 深入理解java虚拟机学习笔记(二)垃圾回收策略

    上篇文章介绍了JVM内存模型的相关知识,其实还有些内容可以更深入的介绍下,比如运行时常量池的动态插入,直接内存等,后期抽空再完善下上篇博客,今天来介绍下JVM中的一些垃圾回收策略.        一. ...

  4. 《深入理解java虚拟机》笔记(5)垃圾回收算法及垃圾收集器

    一.标记-清除算法 算法:分为标记和清除两个阶段,首先标记出所有需要回收的对象,再对标记对象进行回收. 不足之处:效率不高,会产生大量不连续内存碎片,导致下次分配较大内存时,若内存不足不得不触发垃圾回 ...

  5. 推荐收藏系列:一文理解JVM虚拟机(内存、垃圾回收、性能优化)解决面试中遇到问题(图解版)

    欢迎一起学习 <提升能力,涨薪可待篇> <面试知识,工作可待篇 > <实战演练,拒绝996篇 > 欢迎关注我博客 也欢迎关注公 众 号[Ccww笔记],原创技术文章 ...

  6. jvm(四):垃圾回收

    垃圾回收我们主要从以下三个方面进行描述 垃圾对象的判断 目前判断对象为垃圾对象有两种方法:引用计数法,可达性分析法,目前普遍是的是可达性分析法 可达性分析法的实现原理: 定义gcroot一直往下找,如 ...

  7. JAVA高级篇(四、JVM垃圾回收和调优)

    本文转自https://zhuanlan.zhihu.com/p/25539690 JVM GC(垃圾回收机制) 在学习Java GC 之前,我们需要记住一个单词:stop-the-world .它会 ...

  8. 第四章 JVM垃圾回收算法

    说明:在阅读本篇之前,需要知道怎么判断对象的存活与否,见<第三章 JVM内存回收区域+对象存活的判断+引用类型+垃圾回收线程> 注意:本文主要参考自<分布式Java应用:基础与实践& ...

  9. 理解闭包的微观世界和JS垃圾回收机制

    function a() { ; function b() { alert(++i); } return b; } var c = a(); c(); 一.闭包的微观世界 如果要更加深入的了解闭包以及 ...

  10. 【Java学习笔记】Java的垃圾回收机制

    搬以前写的博客[2014-12-30 15:07] 以前很少关注内存的问题,基本没有关注,这方面的小白,原因在于自己都是写的自我娱乐的小程序,不关注性能,不是提供服务.而企业级别的应用在程序稳健性方面 ...

随机推荐

  1. linux c 常常混淆的概念

    指针函数 and 函数指针 指针函数是指带指针的函数,即本质是一个函数.函数都有返回类型(假设不返回值,则为无值型),仅仅只是指针函数返回类型是某一类型的指针. 定义格式 类型名 *函数名(函数參数列 ...

  2. Unity3D学习笔记——Rigdbody刚体组件

    Rigdbody刚体组件:必须和碰撞体(Colliders)一起使用,否则会发生穿过的现象.碰撞体(Colliders)不是必须和刚体一起使用. 刚体的作用:使游戏物体能获得重力,接受外界的受力和扭力 ...

  3. java前端传入的json字符串保存到表中的方法

    表 service_goods_base 字段如下: 传入的json 字符串: servicePictureArray  :  [{"picServiceUrl": "h ...

  4. 如何解决mac下MAMP不能重启apache server的问题

    第一步:检查问题  在终端输入:sudo /Applications/MAMP/Library/bin/apachectl start  终端会提示你那个目录下的那个文件出现了什么问题 第二步:逐一排 ...

  5. haml入门

    1.什么是Haml Haml是HTML abstraction markup language,遵循的原则是标记应该是美的.Haml能够加速和简化模版,长处是简洁.可读.高效. 2.erbm模板和ha ...

  6. Python将数据保存到CSV中

    #coding:utf-8import csv headers = ['ID','UserName','Password','Age','Country'] rows = [(1001,'qiye', ...

  7. 人工智能-基于百度baidu-ai和图灵机器人实现学说话机器人

    本文引用了2个js文件,这里提供下CDN资源,! <script type="application/javascript" src="https://cdn.bo ...

  8. Android-自己定义meta-data扩展数据

    版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/wwj_748/article/details/25079991 Android-自己定义meta-d ...

  9. 脉冲神经网络及有监督学习算法Tempotron

    接下来一段时间开启脉冲神经网络模型的探索之旅.脉冲神经网络有更强的生物学基础,尽可能地模拟生物神经元之间的连接和通信方式.其潜在能力较强,值得踏进一步探索. 构建脉冲神经网络模型,至少需要考虑三点:1 ...

  10. SMW0 上传问题?

    *SMW0 和 OAOR 的区别在哪3个方面? SMW0 上传 出现: 没有指派至MIME 类型