《深入理解計算機系統》筆記:幾個重要概念
阿新 • • 發佈:2018-12-15
執行程式系統
編譯系統
- 從原始碼文字檔案到可執行目標檔案的轉化由編譯系統(compilation system)完成
- 前處理器(cpp):hello.c —> hello.i
- 根據以字元
#
開頭的指令修改原始程式
- 根據以字元
- 編譯器(cc1):hello.i —> hello.s
- 將預處理之後的文字檔案翻譯為組合語言程式(依然是文字檔案)
- 彙編器(as):hello.s —> hello.o
- 將組合語言程式翻譯成一系列機器語言指令,然後將機器語言指令打包成可重定位目標程式
- 連結器(ld):hello.o + printf.o —> hello
- 將程式用到的其他模組與當前程式連結到一起,最終得到可執行目標檔案
- 前處理器(cpp):hello.c —> hello.i
程式計數器 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 系統函式呼叫讀寫檔案來實現
資訊儲存
字
- 任一計算機的字長指明瞭整數和指標資料的標稱大小
- 字長決定了虛擬地址空間的最大大小,對於字長為 的機器,其虛擬地址的範圍是
無符號數
問題程式碼一
- 當
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 << 3) + (x << 2) + (x << 1)
,或更進一步優化為(x << 4) - (x << 1)
- 可優化為
除以 2 的冪
- 整數除法(至少 30 個時鐘週期)比整數乘法更慢