preface 前言
原文摘抄
Learning how computer systems work from a programmer's perspective is great fun, mainly because you can do it actively. Whenever you learn something new, you can try it out right away and see the result firsthand. In fact, we believe that the only way to learn systems is to do systems, either working on concrete problems or writing and running programs on real systems.
这段话可以说是贯穿了整本书的中心思想。
如果将编写程序视作我们从计算机的消费者到计算机的生产者的开端。
大多数人其实是以学习数学的模式开始学习:认识抽象实体、为这些抽象实体创建规则与方法、用抽象的事物去解决问题。
然而,虽然数学与计算机科学息息相关,好的数学思维能帮助你更好地学习计算机科学,二者之间存在着本质的区别 —— 抽象并不是计算机科学的基石。
试想一下,一张图片,这是肉眼所看到的;一个链接,这是 markdown 所看到的;二进制数据,这是计算机系统所看到的。
同样的事物在不同的层级有着不同的表示,哪怕看似简单的算术运算也一样,在第二章中,我们将围绕二进制数据在算术层面的编码展开。
原文摘抄
Having a solid understanding of computer arithmetic is critical to writ-ing reliable programs. For example, programmers and compilers cannot re-place the expression
(x<y)
with(x-y < 0)
, due to the possibility of overflow. They cannot even replace it with the expression(-y < -x)
, due to the asymmetric range of negative and positive numbers in the two's-complement representation. Arithmetic overflow is a common source of programming errors and security vulnerabilities, yet few other books cover the properties of computer arithmetic from a programmer's perspective.
在编程过程中我们有时会遇见一些匪夷所思的情况,它们极有可能是被称为 UB(Undefined Behavior)的情况。了解在补码体系下可能会发生 UB 的情况并规避它们是至关重要的。
连简单的算术运算都存在高层次抽象无法注意到的盲区,作为一个程序员,你的程序真的能如愿按照你的预设运行吗?在第三章中我们将学习程序的机器级表示。
原文摘抄
We also use the machine-level view of programs as a way to understand common code security vulnerabilities, such as buffer overflow, and steps that the programmer the compiler, and the operating system can take to reduce these threats. Learning the concepts in this chapter helps you become a better programmer, because you will understand how programs are represented on a machine. One certain benefit is that you will develop a thorough and concrete understanding of pointers.
学习这章能够理解一些行为为什么在编程中被视为禁忌,也能理解一些约定俗成的习惯的来由,为你的编程之旅祛魅。
第四章较偏硬件,可以粗略阅读仅作了解,关于流水线的一些性质可以帮助你写出更具有空间局部性(Spatial Locality)与时间局部性(Temporal Locality)的代码。
如果所有的程序本质上都是机器码,是什么决定了他的速度,而我们又该如何提升程序的效率呢?学过算法的同学都知道,在编程之前设计一个良好的算法可以在数量级上对程序进行降维。然而,考虑到在实际情况下算法面临得常常是多组小数据,这时候常数级别的优化比数量级优化更为显著。
原文摘抄
We introduce a simple operational model of how modern out-of-order processors work, and show how to measure the potential performance of a program in terms of the critical paths through a graphical representation of a program. You will be surprised at how much you can speed up a program by simple transformations of the C code.
在第五章中,我们将围绕循环展开这一方法,以时间局部性的视角,学习如何通过简单的 C 代码转换,加快程序的速度。
流水线是这样的,计算机系统只需要执行指令就好了,程序员如何写出时间局部性良好的程序考虑的就多了。
那么在第六章中,我们再次直面计算机系统中一大关键抽象 —— 储存。相信很多人应该了解,内存这个词,可以指 RAM (Random-Access Memory),也可以指磁盘(disk)
对,对吗?
原文摘抄
We describe how these storage devices are arranged in a hierarchy. We show how this hierarchy is made possible by locality of reference. We make these ideas concrete by introducing a unique view of a memory system as a "memory mountain" with ridges of temporal locality and slopes of spatial locality. Finally, we show you how to improve the performance of application programs by improving their temporal and spatial locality.
是什么原因使得内存无论何时都是计算机系统中的稀缺资源,我们又该以何种方式为程序分配这样稀缺的资源,这是我们将在第六章学习的。
在代码开头,我们总会写上形形色色的 include,这些 include 都代表了些什么,编译器是如何将名称与值绑定在一起,为了让所有程序用一样的 scanf 与 printf,计算机系统使用了怎样的技巧?
原文摘抄
This chapter covers both static and dynamic linking, including the ideas of relocatable and executable object files, symbol resolution, relocation, static libraries, shared object libraries, position-independent code, and library interpositioning. Linking is not covered in most systems texts, but we cover it for two reasons. First, some of the most confusing errors that programmers can encounter are related to glitches during linking, especially for large software packages. Second, the object files produced by linkers are tied to concepts such as loading, virtual memory, and memory mapping
在第七章中我们将学习链接器是如何工作的,不至于在未来维护项目时,连 make 都用不明白。
Fault&Error 是计算机系统不得不面临的一环,进行一个简单的思考,异常不可能仅靠程序自己解决,万一解决异常的程序也发生异常怎么办,为此,计算机系统需要让硬件介入这个过程,也就是信号。处理异常需要信号,而信号可以干许多事情。本章是了解并发的起点。
原文摘抄
In this part of the presentation, we step beyond the single-program model by introducing the general concept of exceptional control flow (i.e., changes in control flow that are outside the normal branches and procedure calls). We cover examples of exceptional control flow that exist at all levels of the system, from low-level hardware exceptions and interrupts, to context switches between concurrent processes, to abrupt changes in control flow caused by the receipt of Linux signals, to the nonlocal jumps in C that break the stack discipline. This is the part of the book where we introduce the fundamental idea of a process, an abstraction of an executing program. You will learn how processes work and how they can be created and manipulated from application programs. We show how application programmers can make use of multiple processes via Linux system calls. When you finish this chapter, you will be able to write a simple Linux shell with job control. It is also your first introduction to the nondeterministic behavior that arises with concurrent program execution.
在第六章中我们已经理解,内存是计算机系统中一种极为稀有的资源。那么,在多个程序同时运行时,我们该如何为它们分配内存呢?为此,虚拟内存诞生了,作为一种管理内存的抽象为计算机系统服务。
原文摘抄
It reinforces the concept that the virtual memory space is just an array of bytes that the program can subdivide into different storage units. It helps you understand the effects of programs containing memory referencing errors such as storage leaks and invalid pointer references. Finally, many application programmers write their own storage allocators optimized toward the needs and characteristics of the application. This chapter, more than any other, demonstrates the benefit of covering both the hardware and the software aspects of computer systems in a unified way. Traditional computer architecture and operating systems texts present only part of the virtual memory story
在余下的十、十一、十二章中我们将学习多个程序之间信息的传递方式,也将初步认识线程这一可以方便共享资源的存在。这部分的书讲得较为杂乱,可以粗略了解一下,具体的可以到 proxy lab 中切身体会。