《深入理解電腦系統》筆記

來源:互聯網
上載者:User

第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低很多了。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.