`
isiqi
  • 浏览: 16490843 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

《深入理解计算机系统》笔记

阅读更多

第0章 绪论
1,不能用x-y<0代替x

第1章 计算机系统漫游
1,区分不同数据对象的唯一方法是通过这些数据的上下文来判断。
2,cache是由静态随机访问存储器(SRAM)实现的。L1位于处理器芯片上,而L2位于主板上,通过高速缓存总线与芯片相连。
3,进程的虚拟地址空间中,代码和数据后台紧随着的是运行时堆。代码和数据区是在进程一旦开始运行时就被制定了大小的,与此不同,作为调用像malloc和free这样的C标准库函数的结果,堆可以在运行时动态的扩展和收缩。栈也可以扩展和收缩。地址空间顶部的四分之一是为内核预留的。

第2章 信息的表示和处理
1,由于表示的精度有限,浮点运算时不可结合的,一般是选择最小的先运算。
2,字长指明整数和指针数据的大小。字长决定的最重要的系统参数是虚拟地址空间的最大大小。
3,float一般为4字节,double一般为8字节,指针一般用的是全字长,32位机上是4字节,64位机上是8字长。
4,在几乎所有的机器上,多字节对象都被存储为连续的字节序列,对象的地址为所使用字节序列中最小的地址。
5,二进制代码很少能在不同机器和操作系统组合之间移植。
6,表达式~0将生成一个全1的掩码,不管机器的字大小是多少。尽管对于一个32位机器同样的掩码可以写出0xFFFFFFF,但是这样的代码是不可移植的。
7,几乎所有的编译器/机器组合都对有符号数据使用算术右移,即在左边补充符号位。
8,C和C++都支持符号和无符号数,但JAVA只支持有符号数。
9,C库中的文件定义了一组常量,用来限定运行编译器的这台机器的不同整形数据类型的范围,如INT_MAX,INT_MIN,UINT_MAX。
10,强制类型转换并没有改变参数的位表示,只是改变了如何将这些位解释为一个数字:
int x = -1;
unsigned ux = (unsigned)x;
这里的ux = 0xffff ffff
11,规则1:当将一个有符号数映射为它相应的无符号数时,负数就被转换成了大的正数,而非负数会保持不变。
规则2:对于小的数(<2^(w-1)),从无符号到有符号的转换将保留数字的原值,对于大的数,数字将被转换为一个负数值。
12,无符号整数加法:
x+y = x+y , x+y<2^w
x+y = x+y-2^w x+y>=2^w
13,有符号整数加法:
x+y = x+y-2^w, x+y >= 2^(w-1) 正溢出
x+y = x+y, 正常
x+y = x+y+2^w, x+y < -2^(w-1) 负溢出
14,二进制补码的非
-x = -2^(w-1), x = -2^(w-1)
-x = -x, x > 2^(w-1)
15,在单精度浮点格式(C中的float)中,s,exp和frac分别为1位,8位,23位,产生一个32位的表示。在双精度格式(C中的double)中,s,exp和frac分别为1,11位,52为,产生一个64位的表示。
16,浮点数的舍入规则是向偶数舍入(round-to-even),或者向最接近的值舍入(round-to-nearest)。
17,浮点加法不具有结合性,浮点加法满足下面的单调性属性:如果a>=b,那么对任何a和b的值,除了x不等于NaN,都有x+a>=x+b。浮点乘法也满足相应的单调性属性。
18,浮点数取非就是简单的对它的符号位去反。float f; f == -(-f)是正确的。
19,看下面这段代码
view plaincopy to clipboardprint?
#include
#include
using namespace std;
void main()
{
double x = 1.3;
double y = 0.4;
if (x + y != 1.7)
cout << "addition failed?" << endl;
}
#include
#include
using namespace std;

void main()
{
double x = 1.3;
double y = 0.4;
if (x + y != 1.7)
cout << "addition failed?" << endl;
}

运行结果将是addition failed?" 。也就是x+y != 1.7原因就是double中保存的是近似值

,而不是精确值1.7.

正确的写法应该如下:
view plaincopy to clipboardprint?
#include
#include
using namespace std;
const double epsilon = 0.000001;
bool about_equal(double x, double y)
{
return (x < y + epsilon) &&
(x > y - epsilon);
}
void main()
{
cout << "1.3 + 0.4 == 1.7: " <<
(1.3 + 0.4 == 1.7) << endl;
cout << "about_equal(1.3 + 0.4, 1.7): " <<
about_equal(1.3 + 0.4, 1.7) << endl;
}
#include
#include
using namespace std;

const double epsilon = 0.000001;

bool about_equal(double x, double y)
{
return (x < y + epsilon) &&
(x > y - epsilon);
}

void main()
{
cout << "1.3 + 0.4 == 1.7: " <<
(1.3 + 0.4 == 1.7) << endl;
cout << "about_equal(1.3 + 0.4, 1.7): " <<
about_equal(1.3 + 0.4, 1.7) << endl;
}

第3章 程序的机器级表示
1,Linux使用了平面寻址方式(flat addressing),在这种寻址方式中,程序员将整个存储空间看作一个大的字节数组。
2,IA32中传送指令的两个操作数不能都指向存储器位置。
3,根据惯例,所有返回函数或指针值的函数都是通过将结果放在寄存器%eax中来达到目的的。
4,移位量可以是一个立即数,或者放在单字节寄存器元素%cl中。
5,函数的第一个,第二个,第三个参数分别存放在存储器中相对于%ebp中地址偏移量8,12,16的地方。
6,C中,所有的循环都会转换成do-while的形式。
7,根据惯例,寄存器%eax,%edx,%ecx被划分为调用者保存的寄存器,其余的三个(%ebx,%esi,%edi)被划分为被调用者保存的寄存器。
8,
view plaincopy to clipboardprint?
call next
t:
popl %eax ;%eax中保存的是popl指令的地址
call next
next:
popl %eax ;%eax中保存的是popl指令的地址这是IA32中将程序计数器中的值放入证书寄存器的唯一方法。

9,联合(union),用关键字union来声明,允许用几种不同的类型来引用一个对象。一个联合的总的大小等于它最大域的大小。

第5章 优化程序性能
1,代码移动(code motion):包括识别出要执行多次(例如,在循环里)但是计算结果不会改变的计算,因而我们可以将计算机移动到代码前面的,不会被多次求值的部分。
2,消除不必要的引用,比如我们在循环中要不停的将某个值赋给一个指针,我们可以定义一个变量,现将每次求得的值赋给此变量,最后在把变量的值赋给指针。
3,超标量(superscalar):可以在每个时钟周期执行多个操作,而且是乱序的。
4,在一个IA32处理器上,所有的浮点操作都是以扩展的80位精度执行的,而浮点寄存器也是按照这个格式存储值的。只有当寄存器中的值写入存储器中时,才把它转换成32位或64位格式。
5,剖析程序(UNIX平台):在编译时加上-pg的参数,这样,在执行程序的过程中会产生一个gmon.out文件,然后执行gprof a.out 就可以了。
6,存储器别名和过程调用会严重限制编译器执行大量优化的能力。

第6章 存储器层次结构
1,如果你的程序需要的数据存储在CPU寄存器中,那么在执行期间,在零个周期内就能访问到它们。
2,SRAM将每个位存储在一个双稳态存储器单元cell里,每个单元是用一个六晶体管电路来实现的。
3,DRAM将每个位存储为对电容的充电,与SRAM不同,DRAM存储器单元对干扰非常敏感。当电容的电压被扰乱后,它就永远不会恢复了。泄漏电流的各种因素会导致DRAM单元在10---100毫秒时间内失去电荷。
4,一个d*w的DRAM总共存储了dw位信息,其中d个超单元,每个超单元有w位。
5,对扇区的访问时间有三个主要的部分:寻道时间,旋转时间和传送时间。
6,I/O桥接器连接系统总线,存储器总线和I/O总线。
7,重复引用同一个变量的程序有良好的时间局部性;对于取指令来说,循环有好的十件和空间局部性,循环体越小,循环迭代次数越多,局部性越好;对于具有步长为k的引用模式的程序,步长越小,空间局部性越好。具有步长为1的引用模式的程序有很好的空间局部性,在存储器中以大步长跳来跳去的程序空间局部性会很差。
8,高速缓存包括直接映射高速缓存(E=1),组相连高速缓存(1

第7章 链接
1,C源代码文件扮演模块的角色。任何声明带有static属性的全局变量或者函数的哦是模块私有的。类似的,任何声明为不带static属性的全局变量和函数都是公共的,可以被其他模块访问。尽可能用static属性来保护变量和函数是很好的编程习惯。
2,连接器解析多处定义的全局符号时的规则:函数和已初始化的全局变量是强符号,未初始化的全局变量是弱符号。规则1:不允许有多个强符号。规则2:如果有一个强符号和多个弱符号,那么选择强符号。规则3:如果有多个弱符号,那么从这些弱符号中任意选择一个。
3,重定位就是合并输入模块,并为每个符号分配运行时地址。
4,在可执行文件中是完全链接的(已被重定位),所以它不再需要.rel节了。
5,加载:将程序拷贝到存储器并运行。
6,共享库是致力于解决静态库缺陷的新产物。共享库是一个目标模块,在运行时,可以加载到任意的存储器地址,并在存储器中和一个程序连接起来。这个过程称为动态链接,是由一个动态连接器来执行的。共享库的一个主要目的就是允许多个正在运行的进程共享存储器中相同的库代码,因而节约了存储器的资源。

附:
1,在C++中,数组下标的最大值是max(int32),如何在32位机器上突破这个限制?不能!因为C++的数组操作在汇编层会按照基地址+偏移寄存器的形式访问。32位机器上的偏移寄存器只有32位。所以,不能突破。
2,在类规模很小,但需要产生的对象数量巨大(如K,M级别)时,用new申请堆内存效率高,还是直接实例化对象的效率高?二者的上限分别取决于哪一块内存的容量?实例化效率高,这个是对程序栈直接做压栈弹栈,比堆分配要高的多。堆还要记录分配链的起始,中止地址。栈的上限取决于编译时分配的栈长度,堆取决于操作系统提供的内存大小。也就是说,栈空间要远远小于堆空间,而且系统也会使用栈,比如在掉函数时,参数的传递和返回值都是通过栈操作完成的。如果在栈上开大对象造成栈空间用完,系统要么死锁,要么退出。如果要实例化大量的小对象,最好在程序开始时申请一块大内存自己管理,然后小对象用到时,从这块大内存中做分配,也就是内存池技术,尤其是那种小对象的大小固定时,这种方法更有效。
3,数组和STL的性能比较?单纯从访问效率角度讲,数组效率高(包括时间和空间效率),但加入插入,删除,查找,排序等操作后,数组的效率就比STL低很多了。

分享到:
评论

相关推荐

    深入理解计算机系统笔记

    以上内容仅是深入理解计算机系统笔记的一部分,完整理解还需要深入学习计算机体系结构、编译原理、操作系统等领域的知识。通过这些理解,我们可以更好地设计、优化和调试程序,提升计算机系统的整体性能。

    Eandal Bryant_深入理解计算机系统笔记

    《深入理解计算机系统》是Randal E.Bryant和David O’Hallaron合著的一本经典教材,本书全面探讨了计算机系统的运作原理。以下是对各章节核心知识点的详细阐述: **第一章 计算机系统漫游** 计算机系统的核心概念...

    深入理解计算机系统学习笔记

    ### 深入理解计算机系统的关键知识点 #### 计算机系统的组成与工作原理 《深入理解计算机系统》这本书旨在帮助读者从多个角度全面了解计算机系统的工作机制。它不仅仅局限于介绍计算机硬件的基本构成,还深入探讨...

    深入理解计算机系统mobi格式,kindle版

    《深入理解计算机系统》是计算机科学领域的一本经典著作,主要涵盖了计算机系统的基础知识和深入原理。这本书由Randal E. Bryant和David R. O'Hallaron合著,旨在帮助读者从硬件到软件,从底层到高层全面理解计算机...

    深入理解计算机系统的笔记

    ### 深入理解计算机系统的笔记 #### 一、程序的基本组成 计算机程序的基本组成要素主要包括以下几个方面: 1. **算术和逻辑操作**:这些是程序中最基本的操作,用于处理数值计算和逻辑判断。 2. **存储访问**:...

    程序员终身必读-深入理解计算机系统(带笔记).part1

    这本书有多经典就不再赘述了。由于是图片书,所以有点大。不过效果还可以,上面有一些我个人的笔记,相信对阅读有些帮助。建议阅读3遍以上,多多益善。可以作为程序员终身发展的陪伴读物,良友啊。

    《深入理解计算机系统》第3版中文笔记

    《深入理解计算机系统》第三版是一本经典的计算机科学教材,旨在帮助读者全面了解计算机系统的运行机制。这本书结合了《计算机是怎样跑起来的》和《程序是怎样跑起来的》中的核心概念,通过综合讲解,使读者能够从...

    深入理解计算机系统(英文版)

    本书的最大优点是帮助读者理解概念,让读者很清楚地在脑海中构造一个层次型的计算机系统,从最低层数据在内存中的表示(如我们一直陌生的浮点数表示),到流水线指令的构成,到虚拟存储器,到编译系统,到动态加载库...

    2.1深入理解计算机系统(原书第三版).rar

    《深入理解计算机系统》是计算机科学领域的一本经典著作,其第三版更是汇集了作者多年教学与实践经验的精华。这本书全面、深入地介绍了计算机系统的各个方面,帮助读者从硬件到软件,从底层到高层,建立起完整的...

    CSAPP(深入理解计算机系统)

    本书的最大优点是帮助读者理解概念,让读者很清楚地在脑海中构造一个层次型的计算机系统,从最低层数据在内存中的表示(如我们一直陌生的浮点数表示),到流水线指令的构成,到虚拟存储器,到编译系统,到动态加载库...

    CSAPP自学笔记,深入理解计算机系统

    CSAPP自学笔记,深入理解计算机系统 本资源摘要信息将对计算机系统的各个组件进行详细的介绍,从中央处理单元(CPU)到浮点运算单元(FPU),从随机存取存储器(RAM)到基本输入输出系统(BIOS),从通用串行总线...

    学习笔记-深入理解计算机系统-第二章.7z

    《深入理解计算机系统》是计算机科学领域的一本经典教材,主要涵盖了计算机硬件、软件以及它们之间的交互。第二章通常会涉及计算机系统的基础架构,包括处理器、内存系统、输入/输出设备以及程序执行的低级概念。...

    学习笔记-深入理解计算机系统-第一章.7z

    《深入理解计算机系统》是计算机科学领域的一本经典教材,主要涵盖了计算机硬件、操作系统、编译器、存储系统以及网络等方面的知识。第一章通常会作为基础,介绍计算机系统的整体架构和基本概念,帮助读者建立起对...

    csapp-chapter01-Englsh-note 深入理解计算机系统第一章英文笔记

    深入理解计算机系统是计算机科学中的核心课程,第一章主要介绍了计算机系统的基本概念和工作原理。笔记内容涵盖了信息表示、程序翻译、编译系统、处理器硬件组织以及程序执行的过程。 首先,计算机系统是由硬件和...

    深入理解Linux内核笔记

    本读书笔记整理了《深入理解Linux内核》的部分内容,旨在帮助新手理解Linux内核是如何通过硬件支持实现内存寻址和分页的。 首先,Linux的内存寻址使用逻辑地址,由两部分组成:段标识符(Segment Selector)和偏移...

    [深入理解计算机系统(原书第2版)].part13

    《深入理解计算机系统》是计算机科学领域的一本经典教材,主要涵盖了计算机系统的各个方面,包括处理器架构、内存系统、输入/输出、编译器、操作系统以及网络等核心主题。该书的第二版通常会包含更新的内容,以反映...

    程序员终身必读-深入理解计算机系统(带笔记).part3

    本书有多经典就不再赘述了。由于是图片书,所以有点大。不过效果还可以,上面有一些我个人的笔记,相信对阅读有些帮助。建议阅读3遍以上,多多益善。可以作为程序员终身发展的陪伴读物,良友啊。

Global site tag (gtag.js) - Google Analytics