• 【读书笔记】程序员的自我修养总结(六)


    【读书笔记】程序员的自我修养总结(六)

    标签: 【编程开发】


    声明:引用请注明出处http://blog.csdn.net/lg1259156776/


    说明:这是程序员的自我修养一书的读书总结,随着阅读的推进,逐步增加内容。
    本文主要介绍可执行文件的装载与进程


    程序与进程的区别

    程序是静态的,指的是一些预先编译好的指令和数据集合的一个文件;而进程实际上就是运行着的程序,是动态的。

    虚拟地址空间

    程序运行起来后将拥有独立的虚拟地址空间 virtual address space,其大小由计算机的硬件平台决定,具体地说是由CPU的位数决定。硬件决定了地址空间的最大理论上限,即硬件寻址空间大小,比如32bits的CPU,其寻址的能力只有0(2321),对应为4GB的虚拟空间,比如win7系统32位的CPU,其外扩的内存条只能支持最多4GB,多了也无法访问。而现在一般的硬件平台都是64bits,其可拓展的寻址空间几乎是无限的。

    从程序的角度看,可以通过C语言程序指针所占的空间来计算虚拟地址空间的大小,一般来说,C语言指针大小的位数与虚拟空间的位数相同,32bits平台下指针为32位的,4个字节;64bits平台下的指针是64位的,8个字节。但现在以我的开发来讲大多还是选择win32平台进行,这并没有什么区别。

    win32下指针测试:

    #include "stdafx.h"
    int _tmain(int argc, _TCHAR* argv[])
    {
        void * pTest = NULL;
        printf("on win32 platform the pointer has %d bytes!
    ", sizeof(pTest));
        return 0;
    }
    
    output:
    on win32 platform the pointer has 4 bytes!
    

    x64平台下指针测试:

    #include "stdafx.h"
    int _tmain(int argc, _TCHAR* argv[])
    {
        void * pTest = NULL;
        printf("on x64 platform the pointer has %d bytes!
    ", sizeof(pTest));
        return 0;
    }
    
    output:
    on x64 platform the pointer has 8 bytes!
    

    下面主要用32bits的硬件平台进行说明:
    Linux操作系统默认情况下会将虚拟地址空间的高1GB空间预留为操作系统空间,剩余3GB空间是留给进程使用的。

    装载的方式

    程序执行时,需要的指令和数据必须在内存中才能正常运行,但很多情况下程序所需内存数量大于物理内存的数量,此时解决的根本办法当然还是增加内存。相对于磁盘,内存是昂贵也稀有的,所以希望是在不增加内存的情况下,让更多的程序运行起来,尽可能有效地利用内存。根据程序运行时的局部性原理,通常将程序最常用的部分驻留内存,而将一些不常用的数据存放在磁盘里面,这就是动态装入的基本原理。

    覆盖装入和页映射是两种典型的动态装载方法,原则上利用程序的局部性原理,动态装入的思想就是程序用到哪块儿就将哪块装入内存,如果不用就暂时不装入,存放在磁盘上。

    覆盖装入

    程序员编写程序的时候必须手动将程序分割成若干块儿,然后编写小的辅助代码来管理这些模块何时应该驻留内存而何时应该被替换掉。程序员将模块按照它们之间的调用依赖关系组织成树状结构。从树状结构中任意一个模块到树的根(main)模块都叫调用路径,该模块被调用时,整个调用路径上的模块必须都在内存中。禁止跨树间调用。

    页映射

    页映射是虚拟存储机制的一部分,将内存和所有磁盘中的数据和指令按照page页为单位划分成若干个页,装在和操作的对象是页,硬件规定的page大小有4096、8192、2MB、4MB等。

    从操作系统看可执行文件的装载

    进程的建立

    进程最关键的特征是拥有独立的虚拟地址空间,创建一个进程,然后装载相应的可执行文件并执行,在有虚拟存储的情况下,只需做以下三件事:
    1. 创建一个独立的虚拟地址空间
    一个虚拟空间是由一组页映射函数将虚拟空间的各个页映射到相应的物理空间,创建虚拟空间实际上并不是创建空间,而是创建映射函数所需要的相应的数据结构。
    2. 读取可执行文件头,建立虚拟空间与可执行文件的映射关系
    上一步做的是虚拟空间到物理空间的映射关系,这一步做的是虚拟空间与可执行文件的映射关系。程序执行发生页错误时,操作系统从物理内存中分配一个物理页,然后将该缺页从磁盘中读取到内存中,再设置缺页的虚拟页和物理页的映射关系,这样程序才得以正常运行。
    3. 将CPU指令寄存器设置成可执行文件的入口地址,启动运行
    操作系统通过设置CPU的指令寄存器将控制权转交给进程,由此进程开始执行。

    页错误

    上面的步骤执行完以后,可执行文件的真正指令和数据都没有装入到内存中,操作系统只是通过可执行文件头部信息建立起可执行文件和进程虚存之间的映射关系而已。假设程序入口地址为0x08048000,刚好是.text段的起始地址。当CPU打算执行这个地址的指令时,发现页面0x08048000~0x08049000是个空页面,认为是一个页错误,page fault。CPU将控制权交给操作系统,操作系统专门的页错误处理例程处理这种情况,在物理内存中分配一个物理页面,将进程中该虚拟地址与分配的物理页之间建立映射关系,然后把控制权还给进程,进程从刚才页错误的位置重新开始执行。
    随着进程的执行,也错误也不断产生,操作系统会为进程分配相应的物理页面来满足进程执行的需求。当然也有可能进程所需要的内存会超过可用的内存数量,特别是多个进程同时执行的时候,这时候操作系统需要精心组织和分配物理内存,甚至有时候应将分配给进程的物理内存暂时收回等,涉及到了操作系统的虚拟存储管理。


    2015-10-30读书笔记 张朋艺

  • 相关阅读:
    为什么hive表有数据,但count(*)返回0
    数仓建设时,要建历史表,用于保存历史数据,用于日后出问题时,起修复数据的作用。按日期分区,每天都把所有的数据存到当天的分区里
    get_json_object用以获取json类型的字段的值
    str_to_map语句,字符串类型变map类型
    按更新时间取最新记录
    hive临时表
    数仓分层
    次日留存、七日留存
    转义
    数据库三范式
  • 原文地址:https://www.cnblogs.com/huty/p/8518966.html
Copyright © 2020-2023  润新知