您的位置:首页 > 理论基础

深入理解计算机系统:几个重要概念

2018-10-17 19:21 302 查看
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/louzhangpeng/article/details/83116266

执行程序系统

编译系统

  • 从源代码文本文件到可执行目标文件的转化由编译系统(compilation system)完成 预处理器(cpp):hello.c —> hello.i 根据以字符
    #
    开头的指令修改原始程序
  • 编译器(cc1):hello.i —> hello.s
      将预处理之后的文本文件翻译为汇编语言程序(依然是文本文件)
  • 汇编器(as):hello.s —> hello.o
      将汇编语言程序翻译成一系列机器语言指令,然后将机器语言指令打包成可重定位目标程序
  • 链接器(ld):hello.o + printf.o —> hello
      将程序用到的其他模块与当前程序链接到一起,最终得到可执行目标文件

    程序计数器 PC

    • 程序计数器为一个字长(64 位系统中是 8 个字节)的存储设备,是 CPU 的核心
    • 在任何时刻,PC 都指向内存中的某条机器语言指令,也就是说,PC 中保存着一条机器语言指令的地址
    • CPU 不断地执行 PC 指向的指令,然后更新 PC,使其指向下一条指令(前后指令不一定相邻)

    存储器层次结构

    • L0:CPU 寄存器
    • L1 ~ L3:L1 ~ L3 高速缓存(SRAM,静态随机访问存储器)
    • L4:主存(DRAM,动态随机访问存储器)
    • L5:本地磁盘
    • L6:远程存储设备(分布式文件系统、Web 服务器)

    局部性原理

    • 程序具有访问局部区域里的数据的趋势

    操作系统抽象

    进程:对处理器、主存和 I/O 设备的抽象

    • 处理器在多个进程间快速切换,称为上下文切换 单处理器在任一时刻只能执行一个进程的代码
    • 当操作系统把控制权从一个进程转移到另一个进程时,便进行上下文切换: 保存当前进程的上下文
    • 恢复新进程的上下文
    • 将控制权转移到新进程

    线程

    • 一个进程可以由多个线程组成,每个线程都运行在进程的上下文中,并共享相同的代码和全局数据
    • 线程一般比进程高效,多线程之间共享数据也比进程之间容易

    虚拟存储器:对主存和磁盘 I/O 的抽象

    • 每个进程使用专有的虚拟地址空间,从而形成每个进程独占主存的假象
    • 每个进程看到的虚拟地址空间由一组准确定义的区构成,从低地址到高地址依次为: 程序代码和数据
    • 运行时堆
    • 共享库
    • 用户栈
    • 内核虚拟存储器

    文件:对 I/O 设备的抽象

    • 文件就是字节序列,别无其他
    • 每个 I/O 设备都可视为文件
    • 系统的所有输入输出都通过一组 Unix I/O 系统函数调用读写文件来实现

    信息存储

    • 任一计算机的字长指明了整数和指针数据的标称大小
    • 字长决定了虚拟地址空间的最大大小,对于字长为 www 的机器,其虚拟地址的范围是 0∼2w−10 \sim 2^w - 10∼2w−1

    无符号数

    问题代码一

    • length
      0
      时,
      length - 1
      转为最大的无符号数,而
      i
      作为
      int
      型整数,所能包含的数永远小于
      length - 1
    • 同样,当
      length
      大于
      int
      所能表示的最大数时,也会形成无限循环
    float sum_elements(float a[], unsigned length)
    {
    int i;
    float result = 0.0;
    for (i = 0; i <= length - 1; i++) // 正确写法:i < length
    result += a[i];
    return result;
    }

    问题代码二

    • strlen()
      返回的
      size_t
      为无符号类型,有无符号类型参与运算的结果依然是无符号类型,因此
      strlen(str1) - strlen(str2)
      永远不会小于
      0
    size_t strlen(const char* str);
    
    int strlonger(const char* str1, const char* str2)
    {
    return strlen(str1) - strlen(str2) > 0; // 正确写法 return strlen(str1) > strlen(str2);
    }

    问题代码三

    • 如果
      maxlen
      是一个负值,
      len
      便被赋为负值,接着再赋给
      memcpy
      函数中的
      n
      参数,但是参数
      n
      是无符号值,从而转为一个很大的整数
    void* memcpy(void* dest, void* src, size_t n);
    
    #define KSIZE 1024
    char kbuf[KSIZE];
    
    int copy_from_kernel(void* user_dest, int maxlen)
    {
    int len = KSIZE < maxlen ? KSIZE : maxlen;
    memcpy(user_dest, kbuf, len);
    return len;
    }

    整数乘法的优化

    • 整数乘法(至少 10 个时钟周期)通常比加法、减法、移位和位级运算(1 个时钟周期)慢得多

    乘以 2 的幂

    • 对于整数变量
      x
      ,C 表达式
      x << k
      等价于 x×2kx \times 2^kx×2k x×14x \times 14x×14 可优化为
      (x << 3) + (x << 2) + (x << 1)
      ,或更进一步优化为
      (x << 4) - (x << 1)

    除以 2 的幂

    • 整数除法(至少 30 个时钟周期)比整数乘法更慢
    阅读更多
  • 内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: 
    相关文章推荐