计算机系统基础

处理器体系结构

1.书后面的习题很好,要做

2.关于Pipe实现的那些图需要再看,并没有很好的理解

3.处理器设计当中,管理复杂性是首要问题,优化使用硬件资源,在最小的成本下获得最大的性能。

 CPU中的时序电路

  时钟

   低电位

    寄存器输出表现不变

   高电位

    输入信号加载到寄存器

    直到下一个上升沿都保持不变(这时候都是低电位)

 单周期处理器的设计

  慢

  没有充分利用硬件性能

  周期

   Fetch

   Decode

   Execute

   Memory

   Write back

   PC

 流水线处理器

  流水线处理器的基本原理

  流水线设计中的其他问题

 Data Hazard的处理

  暂停

  转发

 其他一些东西

  几种冒险

   加载/使用冒险

   处理ret 返回

   预测错误的分支 控制冒险

   异常

  处理方案

   原则是在正确的情况下,尽可能少的周期达成目标,书里都是通过暂停来调节周期,转发来将(类似于缓存的那种感觉)的数据转发减少等待时间

优化程序性能

 程序性能

  优化程序性能

   高效代码

    通用技巧

     程序是如何编译和执行的

     现代处理器和内存是如何工作的

     如何衡量程序的性能以及找出瓶颈

     如何保持代码模块化的前提下,提高程序性能

    代码移动

     确定结果表达式移到循环外面

    减少计算强度

     用更简单的表达式来完成用时较久的操作

     善用移位,交并异或这种东西

    公共子表达式

     重用部分表达式的结果

    小心过程调用

     频繁调用进进出出带来性能损耗

     必要的调用简化声明为宏,inline

      将其化为调用体的一部分以提高效率

     类似获取长度这种的可以只调用一次存在临时变量里

    注意内存问题

     消除不必要的内存引用

     引入临时变量来解决

    处理条件分支

     参照一些限制因素部分

   重新结合变换

   高级设计

    适当的算法和数据结构的选取

    这才是最重要的

   基本编码原则

    避免限制优化的因素

    消除连续的函数调用

    减少过程调用

    消除不必要的内存引用

   低级优化

    并行

     减少通信量,提高通信粒度

     全局通信尽量使用高效聚合通信算法

      广播

      归约

       Reduce

        多个sender接受数据,combine到一个node上

       All-Reduce

        多个sender接受数据,combine到每一个node上

      数据散发与收集

     挖掘算法的并行度,减少CPU空闲等待时间

     负载平衡

     通信、计算的重叠

     通过引入重复计算减少通信

      一些公共量的计算,可以由一个进程完成然后再发送给其他进程,也可以各进程分别独立计算

      后一个方法性能一般更好

    循环展开

    用功能性的风格重写条件操作,使得编译采用条件数据传送

   其他

    使用高性能的库

    一些好的编程习惯可能会导致性能的恶化

     初始化

     不必要check

     etc.

   一些限制因素

    必需的数据链

    必须的唯一某种功能单元才能执行的多次运算

     线性的感觉

     可能会造成堵塞

    其他

     寄存器溢出

      并行量超过寄存器可用数目

     分支预测和预测错误惩罚

      不要过分担心可预测的分支

      书写适合用条件传送实现的代码

条件传送,先取值,再看条件是否满足

  理解内存性能

   加载的性能

    读

   存储的性能

    写

  特定体系结构或应用特性的性能优化

  确认和消除应用瓶颈

   程序剖析

    -pg

    gprof

   使用剖析程序来指导优化

    实践出真知

    根据分析更容易抓主要矛盾

 最重要的其实是一个好的实现思想(算法,数据结构

 优化编译器的能力和局限性

  第一要务是保证代码按照期望运行

  编译会假装最糟糕的情况来优化

 硬件优化

  超线程技术把多线程处理器内部的两个逻辑内核模拟成两个物理芯片

  指令级并行

  流水线

  自动预取

  分支判断

  乱序指令执行(OoOE Out-of-Order Execution)

OoOE处理的好处随着指令流水线的加深以及主存储器(或缓存存储器)与处理器之间的速度差异的扩大而增长。在现代机器上,处理器的运行速度比内存快很多倍,因此在有序处理器花费大量时间等待数据到达期间,它可能已经处理了很多指令。

   指令获取。

   指令分派到指令队列(也称为指令缓冲区或预留站)。

   该指令在队列中等待,直到其输入操作数可用为止。然后允许该指令在更早,更旧的指令之前离开队列。

   指令被发布到适当的功能单元并由该单元执行。

   结果排队。

   仅在所有较旧的指令的结果写回到寄存器文件之后,该结果才写回到寄存器文件。这称为毕业或退休阶段。

  多级cache

存储器结构及虚拟存储器

 局部性

  两(三)种局部性

   时间局部性

    如果一个信息项正在被访问,那么在近期它很可能还会被再次访问

    程序循环、堆栈等是产生时间局部性的原因

   空间局部性

    在最近的将来将用到的信息很可能与现在正在使用的信息在空间地址上是临近的

   顺序局部性

    除转移类指令外,大部分指令是顺序进行的

    指令的顺序执行、数组的连续存放

     顺序执行和非顺序执行的比例大致是5:1

     对大型数组访问也是顺序的

  一些基本原则

   重复引用相同变量的程序具有良好的时间局部性

   步长越小,空间局部性越好

   对于CPU取指令操作来说,循环具有良好的时间和空间局部性,循环体越小,迭代次数越多,局部性越好

 存储器层级结构

  缓存

   缓存命中

    直接在当前层找到目标块了

   缓存不命中

    在其他层找到了目标块,可能需要用到替换

   缓存不命中的类型

    强制性不命中

     空缓存

     第一次访问的情况下

    冲突不命中

这是由于Cache的放置策略决定的

     同类块的聚集

     映射到了同一个地址但是又需要来回访问,冲突

    容量不命中

     工作集的大小超过了缓存集的大小

   缓存管理

    高速缓存存储器

     组成

      S 表示集合(set)数量

      E 表示数据行(line)的数量

      B 表示每个缓存块(block)保存的字节数目

     空间大小

      C=S×E×B

     通过层级关系简化搜索需要的时间,并且和字节的排布也是一一对应的

  存储层次结构,越贵的部分用的越少

  本质

   每一层存储设备都是较低一层的缓存

   尽量利用局部性提升性能

 存储

  地址空间

   物理地址空间

   虚拟地址空间

  虚拟内存的三个角色

   缓存工具

   内存管理工具

   内存保护工具

    页表高位是权限位

  虚拟存储器

   翻译和映射

   TLB(转换检测缓冲区)

这里关于划分TLBT和TLBI等可以细致去理解一下

    单页表

    多级页表

     一层一层找下去

    虚拟结构

     VPN

      Virtual Page Number

       TLBT

        TLB Tag

       TLBI

        TLB Index

     VPO

      Virtual Page Offset

    物理结构

     PPN

      Physical Page Number

       CT

        Cache Tag

     PPO

      Physical Page Offset

       CI

        Cache Index

       CO

        Cache Offset

    过程简述

     虚拟地址分割成VPN和VPO两块

     在TLB中找 Tag和 Index都对应的,有效的情况下

     得到物理地址的CT,PPO即为VPO

     到缓存中根据CT,CI找行,再根据CO找值

   动态存储器分配

    约束

     不能控制已分配块的数量和大小

     必须立即响应 malloc 请求(不能缓存或者给请求重新排序)

     必须在未分配的内存中分配

     不同的块需要对齐(32 位中 8 byte,64 位中 16 byte)

     只能操作和修改未分配的内存

     不能移动已分配的块

    性能指标

     吞吐量

     内存利用率

      内部碎片

       太小,位置空余

      外部碎片

       太大,空余位置不够放新的

    几种实现

     隐式空闲列表 Implicit List

      通过块的头部保存的信息来找到下一个块

     显式空闲列表 Explicit List

      将分配堆实现成一个链表

       后进先出

       或者按地址顺序维护

     分离的空闲列表 Segregated Free List

为了分配一个给定大小的块,我们检查相应的空闲列表,如果列表非空,简单的分配第一个块的全部,空闲块是不会分割以满足分配请求的,如果列表为空,分配器请求内核额外的存储器片(页大小的整数倍),将这个片分成大小相等的块,形成一个新的空闲列表。要释放一个块,直接插入相应的空闲列表的头部。

优点:分配和释放都是常数时间。每个块大小相等,不分割,不合并。那么一个块的大小就可以从他的地址中推断出来,因为没有合并,所有已经分配块头部就不需要标志位和大小,因此已分配的块就不需要头部也不需要尾部,因为分配和释放操作都是在空闲列表的起始处开始操作,所以列表只需要是单向的。

缺点:容易造成内部和外部碎片,因为空闲块是不会被分割的,所以可能会造成内部碎片,更糟的是,因为不会合并空闲块,所以某种访问模式会引起多的外部碎片(请求大空间块)

2:分离适配:

使用这种方法,分配器维护一个空闲列表的数组,每一个空闲列表是和一个大小类相关联,并且被组织成某种类型的显示或隐式的列表,每个列表包含潜在的大小不同的快,这些块是大小类中的成源(相当于一个列表维系一个块大小范围);

请求一个块,并且对适当的空闲列表做首次适配,查找一个合适的块,如果找到一个,那么我们(可选的)分割他,并将剩余的部分插入当适当空闲列表中去,如果找不到,那么就搜索下一个更大的空闲列表。释放时,执行合并,并讲结构放置到相应的空闲列表中;

3:伙伴系统:

伙伴是分离适配的一种特别,维系2^m大小的空间,为每个块大小2^k维护一个分离空闲列表, 0 <= k <=m ,请求块大小向上取整最接近的2的幂,没有就向2.2^k请求,递归的二分分割,每个剩下的半块(称为伙伴)被放置在相应的空闲列表中,要释放一个大小为2^k的块,我们继续合并空闲的伙伴,当遇到一个已分配的伙伴是,停止。

给定地址和块的大小,很容易算出他的伙伴的地址,

一个块大小为32字节:

xxxxxx......x00000;

伙伴地址:

xxxxxx......x10000

      维护多个空闲列表

      按大小分成多个数组,到对应的列表里去查找,找不到找下一个同类或更大的这样子

      三种方法

       简单分离存储

       分离适配

       伙伴系统

     按照大小对块进行排序 Blocks Sorted by Size

    确定合适空间的方法

     First Fit: 每次都从头进行搜索,找到第一个合适的块,线性查找

      需要找较多的块

       有一定的碎片

     Next Fit: 每次从上次搜索结束的位置继续搜索,速度较快,但可能会有更多碎片

      找最少的块,有最多的碎片

     Best Fit: 每次遍历列表,找到最合适的块,碎片较少,但是速度最慢

      找最多的块,有最少的碎片

  高速缓存

   高速缓存对性能的影响

    指标

     不命中率

      不命中数量/引用数量

     命中率

     命中时间

      组选择+行确认+字选择总时间

     不命中惩罚

      额外的时间消耗

       L1--L2 数十个周期

       L1--L3 60个周期

       L1--主存 200个周期

    影响因素

     高速缓存大小

      大的缓存提高命中率

      大的缓存运行更慢

     块大小

      大块可以更好的利用空间局部性

      大块影响时间局部性程序中的命中率

      大块不命中处罚也变大,因为传送时间变长

     相联度(E的数目)

      较高的相联度降低了高速缓存由于冲突不命中出现抖动的可能性

      较高的相联度成本较高

      较高的相联度速度难以变快,需要额外的LRU状态位,控制逻辑

      较高的相联度命中时间增加,还会增加不命中处罚

      因此会比较折中的采取

       Intel Core 7的例子

        L1,L2 8路组相联

        L3 16路组相联

     写策略

      直写

       有写缓冲区

       读不命中概率没这么大

       相当于立刻写

      写回

       传送较少

       更多的内存的带宽用于执行DMA的I/O设备

       相当于过一段时间写

      故而,高速缓存越往下层,越可能使用写回而不是直写

   计算机高速缓存器原理

    直接映射高速缓存

     组选择

     行匹配

      命中

       有效位为1

       标记位与地址上标记位一致

     字抽取

      命中时根据B的偏移量来选择字节

     行替换

      不命中

       替换一个行

    组相联高速缓存

     替换原则(一般最不常使用原则LFU最近最少使用原则LRU)

    全相联高速缓存

     一个组

     所有的高速缓存

     地址被划分成一个标记和一个块偏移

     造价高,只适合做小的高速缓存

      如缓存页表项的TLB

    写

     直写

      总线l流量占用

     写回

缓存不会立即把写操作传递到下一级,而是仅修改本级缓存中的数据,并且把对应的缓存段标记为“脏”段。脏段会触发回写,也就是把里面的内容写到对应的内存或下一级缓存中。回写后,脏段又变“干净”了。当一个脏段被丢弃的时候,总是先要进行一次回写。回写所遵循的规律有点不同。

      需要额外的修改位

    写不命中

     写分配

      加载相应块到高速缓存,更新高速缓存块

       通常与写回一起

        建议这种组合(在考虑程序设计中

     非写分配

      直接写到低层,避开高速缓存

       通常与直写一起

    缓存一致性协议

     窥探snooping协议

      告诉你我开始读写某个缓存区域了

     MESI协议

MESI定律:在所有的脏缓存段(M状态)被回写后,任意缓存级别的所有缓存段中的内容,和它们对应的内存中的内容一致。此外,在任意时刻,当某个位置的内存被一个处理器加载入独占缓存段时(E状态),那它就不会再出现在其他任何处理器的缓存中。

      modified

       该缓存行只被缓存在该CPU的缓存中

       并且是被修改过的(dirty)

       需要在某个时间点写回

       写回主存之后再变为exclusive

      exclusive

对于M和E状态而言总是精确的,他们在和该缓存行的真正状态是一致的。而S状态可能是非一致的,如果一个缓存将处于S状态的缓存行作废了,而另一个缓存实际上可能已经独享了该缓存行,但是该缓存却不会将该缓存行升迁为E状态,这是因为其它缓存不会广播他们作废掉该缓存行的通知,同样由于缓存并没有保存该缓存行的copy的数量,因此(即使有这种通知)也没有办法确定自己是否已经独享了该缓存行。

       该缓存行只被缓存在该CPU的缓存中

       该状态可以在任何时刻当有其它CPU读取该内存时变成共享状态(shared)

       当CPU修改该缓存行中内容时,该状态可以变成Modified状态

      shared

       该状态意味着该缓存行可能被多个CPU缓存

       当有一个CPU修改该缓存行中,其它CPU中该缓存行可以被作废(invalid)

      invalid

       该缓存是无效的(可能有其它CPU修改了该缓存行)

   设计因素

    - 高速缓存大小,越小,速度越快。

    - 块大小,高速缓存与内存间的数据交换单位。块越大,命中率越高。但是块变得更大时,会导致数据重复替换可能性提高。

    - 映射函数,确定块占据哪个高速缓存单元。其灵活性影响着替换算法的设计。

    - 替换算法,选择替换不久的将来被访问的可能性最小的块。被称作最近最少使用算法(LRU)

    - 写策略,将修改的内容写回内存。写策略规定合适发生存储器写操作。

 垃圾收集

  没有指针指向的地方是垃圾

   标记

   回收

  相关算法

   Mark-and-sweep collection (McCarthy, 1960)

    标记

     初始全部标记为0

     能访问到的标记为1

    扫除

     移除标记为0的

     将标记为1的重置为0

     之后走标记的流程

   Reference counting (Collins, 1960)

    即引用计数

    记录有多少个对象保留对当前对象的引用

    根据这个来删除

   Copying collection (Minsky, 1963)

    内存分块

    做删除操作的时候将旧内存复制到新的地方

    清空旧的块

    新空间满了之后,倒转再做一次

    空间不够一般垃圾收集器会告诉你不行了然后溜了

   Generational Collectors(Lieberman and Hewitt, 1983)

    一代一代的内存块充当世代的垃圾收集器

    和复制内存的方法类似,将活动对象传递下去

    第n代使用其他方法来回收垃圾

    一个问题

     如果较早的一代中的对象指向较新的一代中的对象,则当我们垃圾回收较新的一代时,我们将破坏较旧的对象

 内存陷阱

  未引用的指针

  访问未初始化的内存

  Overwriting Memory

   分配了错误的大小

   超出了分配的空间

   溢出(攻击)

   指针与对象引用错误

   size(int)和size(* int)这样的使用错误

  指向无效变量

  重复多次释放同一个块

  引用释放了的块

  内存泄漏

 Others

  机械硬盘

   容量 Capacity = 每个扇区的字节数(bytes/sector) x 磁道上的平均扇区数(avg sectors/track) x 磁盘一面的磁道数(tracks/surface) x 磁盘的面数(surfaces/platter) x 硬盘包含的磁盘数(platters/disk)

   读取-->寻找-->旋转延迟-->读取

   7200RPM,400secs/track,平均寻址时间9ms

   总的访问时间 Taccess = 寻址时间 Tavg seek + 旋转时间 Tavg rotation + 传输时间 Tavg transfer

    Tavg rotation = 1/2 x (60 secs / 7200 RPM) x 1000 ms/sec = 4 ms

     平均取转半圈的情况,1000ms/sec进行单位换算

    Tavg transfer = 60 / 7200 RPM x 1/400 secs/track x 1000 ms/sec = 0.02 ms

     传输时间,1000ms/sec进行单位换算

    Taccess = 9 ms + 4 ms + 0.02 ms

   主要决定访问时间的是寻址时间和旋转时间

    读取第一个比特耗时很长,之后几乎可以忽略不计

    硬盘比SDRAM慢40,000倍,比DRAM慢2,500倍

  固态硬盘

   Block

    Page

   对页进行写操作需要先将block清空(需要移动其他page)

   一个block大概写入100,000次会报废

   设计原因,比机械硬盘快,连续访问比随机访问快很多

链接、进程及并发编程

 链接

  动态链接库

   1.多个应用程序共享代码和数据

   2.在钩子程序过滤系统消息时必须使用动态连接库。

钩子截获消息流

   3.动态链接库以一种自然的方式将一个大的应用程序划分为几个小的模块,各个模块可以独立升级

   4.对于不同的版本,可以使用不同的动态链接库

   5.拓展研发工具的功能,由于DLL是和语言无关的,因此能创建一个DLL,被C++、VB或所有支持动态链接库的语言调用

    弥补语言的不足

  静态链接

   外部函数与变量的集合体

   解析

    扫描当前命令中的 .o 和 .a 文件

    扫描过程中,维护一个当前未解析引用的列表

    扫描到新的 .o 或 .a 文件时,试图去寻找未解析引用

    如果扫描结束时仍旧有未解析的引用,则报错

   解析Tips

    把静态库都放到后面去

  目标文件

   可重定位目标文件

    Relocatable object file(.o file)

     由对应的.c文件通过编译器和汇编器生成

     包含代码和数据

     可以与其他可重定位目标文件合并创建一个可执行或可共享的目标文件

   可执行目标文件

    Executable object file(a.out file)

     由链接器生成

     可以直接通过加载器加载到内存中充当进程执行的文件

     包含代码和数据

   共享目标文件

    Shared object file(.so file)

     特殊的可重定位目标文件

     可以在链接(静态共享库)时加入目标文件

     或运行时(动态共享库)被动态的加载到内存并执行

   ELF存储结构

    ELF header

     包含 word size, byte ordering, file type (.o, exec, .so), machine type, etc

    Segment header table

     包含 page size, virtual addresses memory segments(sections), segment sizes

    .text section

     代码部分

    .rodata section

     只读数据部分,例如跳转表

    .data section

     初始化的全局变量

    .bss section

     未初始化的全局变量

    .symtab section

     包含 symbol table, procudure 和 static variable names 以及 section names 和 location

    .rel.txt section

     .text section 的重定位信息

    .rel.data section

     .data section 的重定位信息

    .debug section

     包含 symbolic debugging (gcc -g) 的信息

    Section header table

     每个 section 的大小和偏移量

  符号和符号表

   符号表

    结构体数组

    元素

     名称

     大小

     符号的位置

   符号

    全局符号

     在当前模块中定义,且可以被其他代码引用的符号

     例如非静态 C 函数和非静态全局变量

     global

    外部符号

     全局符号

     其他模块定义的,可在当前模块引用的

     external global

    本地符号

     当前模块定义

     只能当前模块引用

     local

   符号解析阶段

    链接器给每个符号应用一个唯一的符号定义

    符号定义是寻找对应符号的标志

    存储

     局部非静态变量会保存在栈中

     局部静态变量会保存在 .bss 或 .data 中

     几个位置

      堆

       存放对象

       可以被多个线程共享

       空间不连续,速度慢,但是灵活

      栈

       存放局部变量

       不可以被多个线程共享

       空间连续,速度快

      方法区

       存放类的信息:代码,局部变量,字符串常量等

       可以被多个线程共享

       空间不连续,速度慢,但灵活

     准则

      引用类型总是被分配到堆上

      基础l类型总是分配到它声明的地方

       成员变量堆内存

       局部变量栈内存

    符号

     强符号

      函数和初始化的全局变量

     弱符号

      未初始化的全局变量

     选取规则

这里需要对几个例子再好好看看

      不能出现多个同名的强符号,不然就会出现链接错误

      如果有同名的强符号和弱符号,选择强符号,也就意味着弱符号是『无效』

      如果有多个弱符号,随便选择一个

      一些戏剧化的事情

       是什么让我觉得戏剧化,,果然写东西还是得写具体一点

     Tips

      减少全局变量的使用

      使用静态变量

      定义全局变量的时候初始化

      注意使用 extern 关键字

   结构关系

    符号声明保存在符号表中

    符号表保存在由汇编器生成的object中

  重定位和加载

   不同的重定位对象文件拼成可执行对象文件

 进程

  异常

   通过异常表确定跳转的异常处理代码位置

   画图,稍微巩固一下

    异常跳转的那个图

   常见

    异步异常

     又称中断

     处理器之外发生的事情引起的

     需要设置处理器的中断指针(interrupt pin)

     处理完成后会返回之前控制流中的『下一条』指令

     常见中断

      计时器中断

      I/O中断

       控制台指令

       输入流,输出流中断了之类的

    同步异常

     陷阱

      Trap

       有意的异常

        返回到下一条指令

         系统调用,断点

     故障

      Fault

       潜在的可恢复的错误

        返回到当前指令

         Page Fault

     终止

      Abort

       不可恢复的错误

        终止当前程序

         非法指令

    系统调用

     read

     write

     open

     close

     stat

      返回文件标识符指向文件的属性

     fork

     execve

     _exit

     kill

  两个抽象

   逻辑控制流

    上下文切换的内核机制

    独占处理器的感觉

   私有地址空间

    虚拟内存的机制

    独占内存的感觉

  进程

   切换

    通过内存到寄存器的载入载出和CPU的调度实现切换

    多核处理器真正实现了部分并行

     共享一部分主存和内存

   控制

    系统调用的错误处理

     对于每个系统调用都应该检查返回值

     当然有一些系统调用的返回值为 void,在这里就不适用

    获取进程信息

     运行

     停止

     终止

     新建

     就绪

    创建进程

    终止进程

     接收到终止信号

     返回到main函数

     调用_exit

   进程图

    满足拓扑排序,就是可能的输出

    

   回收子进程

    父进程回收

    init回收

    需要显式回收

     长期运行的

     例如shell,server

  改变控制流的方式

   跳转和分支

    本地跳转

     goto

    非本地跳转

   调用和返回

   异常控制流

    进程切换

    信号

    非本地跳转

     setjmp

     longjmp

  信号

   进程组

   进程控制和信号

    接收信号

    阻塞信号

    安全处理信号

     规则 1:信号处理器越简单越好

      例如:设置一个全局的标记,并返回

     规则 2:信号处理器中只调用异步且信号安全(async-signal-safe)的函数

      诸如 printf, sprintf, malloc 和 exit 都是不安全的!

     规则 3:在进入和退出的时候保存和恢复 errno

      这样信号处理器就不会覆盖原有的 errno 值

     规则 4:临时阻塞所有的信号以保证对于共享数据结构的访问

      防止可能出现的数据损坏

     规则 5:用 volatile 关键字声明全局变量

需要进一步理解

      这样编译器就不会把它们保存在寄存器中,保证一致性

      修改的值会立刻更新到主存

     规则 6:用 volatile sig_atomic_t 来声明全局标识符(flag)

      这样可以防止出现访问异常

      其实也是个vliatile int声明的计数

   信号

    忽略信号

    终止进程

    捕获信号

     执行信号处理器

     类似于异步处理器

 并发编程

  各种并发编程模式

  共享变量和线程同步

  其他并行问题

  实现

   基于进程

    内核自动管理多个逻辑流

    每个进程有其私有的地址空间(也就是说进程切换的时候需要保存和载入数据)

   基于事件

    由程序员手动控制多个逻辑流

    所有的逻辑流共享同一个地址空间

    这个技术称为 I/O multiplexing

   基于线程

    内核自动管理多个逻辑流

    每个线程共享地址空间

    属于基于进程和基于事件的混合体

 两个概念堆&栈

  堆

   程序员分配释放

   存在二级缓存之中

   生命周期由虚拟机的垃圾回收算法决定

   调用对象速度相对较慢

  栈

   编译器自动分配释放

   存放函数的参数值,局部变量的值等

   存在一级缓存之中

   被调用时处于存储空间

   调用完毕立刻释放

系统级I/O和网络编程

 系统级I/O

  I/O相关概念

   万物皆是IO(文件表示)

  文件及文件操作

   文件描述符

   文件元数据

   重定向

   标准输入输出

  共享文件

   描述符表

   文件表

   v-node表

    存放元数据之类

 网络编程

  客户端-服务器模型

  套接字接口(Socket)

  HTTP请求

  Web服务器

杂项

 Amdahl定律

  S=1/(1-a+a/n)

  a为并行计算所占比例,n为并行处理节点个数,S为并行效果加速比

  根据Amdahl定律,使用多核CPU对系统进行优化,优化的效果取决于CPU的数量以及系统中的串行化程序的比重。CPU数量越多,串行化比重越低,则优化效果越好。仅提高CPU数量而不降低程序的串行化比重,也无法提高系统性能。

  

 古斯塔夫定律

  

  从Gustafson定律中,我们可以更容易地发现,如果串行化比例很小,并行化比例很大,那么加速比就是处理器的个数。只要你不断地累加处理器,就能获得更快的速度。