探索計算機的結構與核心概念

在咱們的生活與工做中所使用到的計算機都是基於馮諾依曼結構實現的,馮諾依曼結構又稱馮諾依曼模型或普林斯頓結構,它是一種將程序指令存儲器和數據存儲器合併在一塊兒的計算機設計概念結構.git

馮諾依曼結構起源於EDVAC(Electronic Discrete Variable Automatic Computer)離散變量自動電子計算機,當時馮諾依曼以技術顧問的身份加入EDVAC項目組,負責總結和詳細說明EDVAC的邏輯設計,直到1945年6月發表了一份長達101頁的報告,這就是計算機史上著名的"101頁報告",該報告明確規定用二進制替代十進制運算,並將計算機分紅五大組件,這一卓越的思想爲電子計算機的邏輯結構設計奠基了基礎,已成爲計算機設計的基本原則.程序員

馮諾依曼結構
馮諾依曼結構

馮諾依曼結構具備如下特色: github

  1. 數據由一個貫穿整個結構的總線來進行傳輸.編程

  2. 存儲器是按地址訪問、線性編址的空間數組

  3. 指令由操做碼和地址碼組成瀏覽器

  4. 數據以二進制編碼緩存

  5. 一個馮諾依曼結構的計算機必須有存儲器,控制單元,運算單元,輸入輸出設備.安全

馮諾依曼結構將CPU與存儲器分開的作法也並不是十全十美,CPU和內存、硬盤等設備的數據傳輸速度不匹配成了總體效率的瓶頸,CPU會在等待數據輸入的時間中空置,許多技術都是爲了解決這個瓶頸,例如DMA(直接內存訪問),在CPU中創建高速緩衝區等.服務器

本文做者爲: SylvanasSun(sylvanas.sun@gmail.com).轉載請務必將下面這段話置於文章開頭處(保留超連接).
本文首發自SylvanasSun Blog,原文連接: sylvanassun.github.io/2017/09/08/…網絡

現代計算機結構


現代計算機是基於馮諾依曼結構的電子計算機.所謂電子計算機,就是是一種利用電子學原理,根據一系列指令對數據進行處理的機器.

晶體管是組成現代電子計算機的最原始的部件(集成電路中含有數以億計的晶體管),它是一種半導體材料(導電性可受控制,範圍可從絕緣體至導體之間),晶體管能夠經過電流的變化,實現電路的切換,這種特性很是適合組成各類邏輯門(與或非)與表示二進制數據.值得一提的是,早期使用繼電器實現邏輯門的計算機體積甚至大到要一整個屋子才能放下.

現代計算機的硬件結構以下圖,雖然多了不少其餘的硬件但與馮諾依曼結構的概念是一致的:

總線


總線是一組貫穿全部硬件結構的電子管道,它攜帶數據並負責在各個部件間交互傳遞.總線傳送的數據一般爲一個定長的字節塊,這個字節塊的長度便是總線的位寬,總線位寬越大,數據傳輸的性能就越高,在32位機器中總線位寬爲4個字節,64位機器中爲8個字節.

有意思的是總線的英文單詞是bus,若是把主板想象成一座城市,那麼總線就像是城市中的公共汽車,它按着多種固定線路不停地來回傳輸數據.

I/O設備


I/O(輸入/輸出)設備是計算機與外部進行聯繫的橋樑,每一個I/O設備都要經過一個控制器或者適配器來與I/O總線相連.

控制器與適配器的區別只在於它們的封裝方式,它們的功能都是爲了讓I/O設備與I/O總線進行鏈接:

  • 控制器是I/O設備自己或者主板上自帶的芯片組

  • 適配器則是插在主板上的外部設備,

在圖中,I/O設備包含鼠標、鍵盤(輸入設備)、顯示器(輸出設備)、磁盤、網絡.

內存


內存也叫主存,它是一個臨時的存儲設備,存儲了運行時的數據(程序與程序處理的數據),以供CPU進行處理.內存是由一組DRAM(動態隨機存取存儲器)芯片組成的,DRAMRAM(隨機存取存儲器)的一種,另外一種爲SRAM(靜態隨機存取存儲器),SRAMDRAM速度更快,但造價也更貴,一般用來實現爲高速緩存區.

32位操做系統中的CPU的最大尋址空間只有2^32字節,換算下來最高內存上限爲4GB,但因爲CPU還要對BIOS和其餘硬件等進行尋址(這些優先級更高),因此用戶實際可用的內存只有3GB左右.

64位操做系統的CPU最大尋址空間足足有2^64字節,也就是16EB(1024GB等於1TB,1024TB等於1PB,1024PB等於1EB),這已是一個沒法想象的數字了,不過這也不必定是夠用的,畢竟誰又能知道將來的數據量會有多龐大呢?

內存具備如下特色:

  • 隨機存取: 當存儲器中的數據被寫入或讀取時,所須要的時間與數據所在的位置無關(從邏輯上,能夠把內存當作一個線性的字節數組,每一個字節都有其惟一的地址(索引),這些地址是從零開始的).
  • 易失性: 若是電源忽然斷開,RAM中的數據就會所有丟失(磁盤能夠將數據持久化地永久保存下來,就算斷電也不會丟失數據).
  • 依賴刷新: RAM使用電容器來存儲數據,當電容器充滿電以後表示1,未充電則表示0.因爲電容器或多或少有漏電的情形,若不做特別處理,電荷會漸漸隨時間流失而使數據發生錯誤.刷新是指從新爲電容器充電,彌補流失了的電荷.DRAM的讀取即有刷新的功效,但通常的定時刷新並不須要做完整的讀取,只需做該芯片的一個列選擇,整列的數據便可得到刷新,而同一時間內,全部相關記憶芯片都可同時做同一列選擇,所以,在一段期間內逐一作完全部列的刷新,便可完成全部存儲器的刷新.須要刷新正好解釋了隨機存取存儲器的易失性.
  • 對靜電敏感: RAM與集成電路同樣,對環境的靜電荷很是敏感,靜電會干擾存儲器內電容器的電荷,致使數據流失,甚至燒壞電路.

CPU


Intel I7 CPU
Intel I7 CPU

Central Processing Unit中央處理單元,簡稱CPU或處理器,CPU包含了馮諾依曼結構中的控制器與運算器,它是解釋或執行存儲在內存中的指令的引擎.CPU比如計算機的大腦,從通電開始,直到斷電,CPU一直在不斷地執行內存中存儲的指令.若是沒有CPU,那麼計算機就會是一臺不會動的死機器了.

所謂指令就是進行指定操做的操做碼,而指令集架構就是這些操做碼的集合,至於微架構是一套用於執行指令集的微處理器設計方法,多個不一樣微架構的CPU可使用同一套指令集,一些常見的指令以下:

  • 加載: 從內存中複製數據(多少個字節取決於總線位寬)到寄存器,以覆蓋寄存器中原來的內容.
  • 存儲: 從寄存器複製數據到內存中的某個位置,以覆蓋這個位置上原有的內容.
  • 操做: 把兩個在寄存器中的數據複製到ALU,ALU對這2個數據進行算術運算,並將結果存放到一個寄存器中,以覆蓋該寄存器中原有的內容.
  • 跳轉: 從指令自己中抽取數據(地址),將它複製到程序計數器中,以覆蓋程序計數器原有的內容.

下面以一個簡單的算術問題1 + 1來大體瞭解一下CPU的工做流程:

  1. 這兩個變量首先會被存儲在內存中.

  2. CPU從內存中讀取指令並刷新程序計數器(每執行完一個指令都要刷新程序計數器).

  3. CPU執行加載指令,經過總線將這兩個變量傳輸(複製)到寄存器.

  4. CPU執行運算指令,從寄存器中複製這兩個變量進行算術運算,並將結果存到寄存器.

  5. CPU執行存儲指令,寄存器經過總線將結果存儲回內存(覆蓋原有位置).

寄存器


寄存器是CPU中的一個存儲部件,能夠認爲它是容量很小但速度飛快的內存,寄存器是與ALU直接交互的存儲設備(無論數據是在內存仍是高速緩衝區,最終都要存到寄存器才能與ALU交互).

CPU架構中,擁有多個寄存器,它們分別擁有各自的用途(指令寄存器,整數寄存器,浮點數寄存器等),且寄存器的數量和它的大小都與指令集架構和機器支持的位寬相關聯(例如x86-64指令集架構(64位指令集架構)中支持64位的通用寄存器與64位整數運算,而x86指令集架構只能支持32位和16位).

程序計數器


程序計數器用於指示將要執行的指令序列,而且不斷刷新指向新的指令地址,根據CPU的實現不一樣,程序計數器可能會指向正在運行的指令地址也可能會是下一個指令的地址.

高速緩衝


因爲寄存器與內存的速度相差過大,爲了不性能上的浪費,在寄存器與內存之間創建數據的緩存區是頗有必要的.

高速緩存是一個比內存更小但更快的存儲設備,且使用SRAM實現,如今的CPU通常都配有三級緩存,L1緩存速度最快但存儲的容量也最小,L2要比L1慢但存儲的容量也更大,以此類推(上一層的存儲器做爲下一層存儲器的高速緩存,也就是說,寄存器就是L1的高速緩存,L1則是L2的高速緩存,L2L3的高速緩存...)....

CPU發起向內存加載數據的請求時,會先從緩存中查找,若是緩存未命中,纔會從內存加載數據,並更新緩存.高速緩存之因此如此有效,主要是利用了局部性原理,即最近訪問過的內存位置以及周邊的內存位置很容易會被再次訪問.而高速緩存中就存儲着這些常常會被訪問的數據.

DMA


DMA全稱爲Direct Memory Access直接內存訪問,它容許其餘硬件能夠直接訪問內存中的數據,而無需讓CPU介入處理.通常會使用到DMA的硬件有顯卡、網卡、聲卡等.

DMA會致使發生緩存不一致的問題,須要額外的進行同步操做保證數據安全.例如,當CPU從內存中讀取數據後,會暫時將新數據寫入緩存中,但尚未將數據更新回內存,若是在這期間發生了DMA,就會讀取到舊的數據.

緩存一致性問題
緩存一致性問題

流水線


流水線又稱管線,是現代CPU中必不可少的優化技術,它將指令的處理過程拆分爲多個步驟,並經過多個硬件處理單元並行執行這些步驟.

管線的具體執行過程很像工廠中的流水線(指令就像在流水線傳送帶上的產品,各個硬件處理單元就像是在流水線旁進行操做的工人),所以而得名爲流水線.

流水線雖然提升了總體的吞吐量,但也是有其缺點的,這是因爲流水線依賴於分支預測,若是CPU預測的分支是錯誤的,那麼整個流水線上的全部指令都要取消,而後從新向流水線填充指令,這項操做是很耗費性能的.

超線程


超線程是一種容許一個CPU執行多個控制流的技術,它複製了CPU中必要的硬件資源(程序計數器、寄存器),來讓其在同一時間內處理兩個線程的工做.

經過超線程技術,可讓一個CPU核心去執行兩個線程,因此一個帶有4核(實體核心)的CPU實際上能夠執行8個線程(邏輯線程).

多核


多核CPU是指將多個核心(也就是CPU)集成到一個集成電路芯片上.每一個核心均可以獨立的執行指令,也就是真正意義上的並行執行.

每一個核心都擁有獨立的寄存器,程序計數器,高速緩存等組件,通常還會有一個全部核心共享的緩存,它是直接與內存連通的緩衝區.

多核CPU與多處理器不一樣,多處理器是將多個CPU封裝在多個獨立的集成電路芯片中,而多核CPU是全部核心都封裝在同一個集成電路芯片中.

操做系統


操做系統是用於管理計算機硬件與軟件的程序,能夠把操做系統當作是應用程序與硬件之間插入的一層軟件,全部應用程序對硬件的操做嘗試都必須經過操做系統.

操做系統須要負責管理與配置內存、調度系統資源的優先次序、管理進程與線程、控制I/O設備、操做網絡與管理文件系統等事務.能夠說操做系統是整個計算機系統中的靈魂所在.

System Call
System Call

操做系統的內核是操做系統最核心的地方,它是代碼和數據的一個集合.當應用程序須要操做系統的某些操做時,會執行一條系統調用(system call)指令,這時,控制權會被移交到內核,由內核執行被請求的操做並返回到應用程序.大多數系統的交互式操做都須要在內核完成,例如I/O、進程管理等.

虛擬內存


虛擬內存是計算機系統內存管理的一種技術,它爲每一個進程提供了一個假象,即每一個進程都在獨佔地使用內存(一個連續的地址空間),而實際上,它一般被分割爲多個物理內存碎片,還有部分暫時存儲在磁盤存儲器上,在須要時進行數據交換.使用虛擬內存會使程序的編寫更加容易,對真實的物理內存的使用也會更加有效率.

進程的虛擬地址空間
進程的虛擬地址空間

每一個進程所能看到的虛擬地址空間大體如上圖所示,每一個區域都有它專門的做用.

  • 內核虛擬內存: 這個區域是爲操做系統內核保留的,它不容許應用程序讀寫這個區域的內容或者直接調用內核代碼定義的函數(只有操做系統內核纔有權限).
  • 共享庫: 以c語音爲例,共享庫是用來存放的是像C標準庫這樣的共享庫的代碼和數據的區域.
  • 程序代碼和數據: 對於全部進程來講,代碼都是從同一固定地址開始,緊接着的是其相對應的數據位置.這片區域就是用來存放代碼和數據的.
  • 堆: 堆內存是指應用程序在運行時進行分配的內存區域,堆能夠在運行時動態地擴展和收縮.像malloc()free()這樣的函數就是在堆內存中進行分配空間與釋放,而相似Java這種更高一級的語言提供了自動內存管理和垃圾回收,不須要程序員手動地分配與釋放堆內存空間.
  • 棧: 棧一樣也是能夠動態地擴展和收縮,它是一個後進先出的容器,主要用於函數調用.當一個函數調用時會在棧中分配空間,當調用結束時,這個函數所佔用的內存空間會一塊兒釋放,無需程序員關心.

進程與線程


進程


進程是操做系統對一個正在運行的程序的一種抽象,它是程序的執行實體,是操做系統對資源進行調度的一個基本單位,同時也是線程的容器.

進程跟虛擬內存同樣,也是操做系統提供的一種假象,它讓每一個程序看上去都是在獨佔地使用CPU、內存和I/O設備.但其實同一時間只有一個進程在運行,而咱們可以邊聽歌邊上網邊碼代碼的緣由實際上是操做系統在對進程進行切換,一個進程和另外一個進程實際上是交錯執行的,只不過計算機的速度極快,咱們沒法感覺到而已.

操做系統會保持跟蹤進程運行所需的全部狀態信息,這種狀態,被稱爲上下文(Context),它包含了許多重要的信息,例如程序計數器和寄存器的當前值等.當操做系統須要對當前進程進行切換時(轉移到另外一個進程),會保存當前進程的上下文,而後恢復新進程的上下文,這時控制權會移交到新進程,新進程會從它上次停下來的地方開始執行,這個過程叫作上下文切換.

操做系統的進程空間能夠分爲用戶空間與內核空間,也就是用戶態與內核態.它們的執行權限不一樣,通常的應用程序是在用戶態中運行的,而當應用程序執行系統調用時就須要切換到內核態,由內核執行.

線程


線程是操做系統所能調度的最小單位,它被包含在進程之中,且一個進程中的全部線程共享進程的資源,一個線程通常被指爲進程中的一條單一順序的控制流.

線程都運行在進程的上下文中,雖然線程共享了進程的資源,但每條線程都擁有本身的獨立空間,例如函數調用棧、寄存器、線程本地存儲.

線程的實現主要有如下三種方式:

  • 使用內核線程實現: 內核線程就是由操做系統內核直接支持的線程,這種線程由內核來完成線程切換調度,內核經過調度器對線程進行調度,並將線程的任務映射到各個處理器上.應用程序通常不會直接使用內核線程,而是使用內核線程的一個接口: 輕量級進程,每一個輕量級進程都由一個內核線程支持,因此它們的關係是1:1的.這種線程的實現方式的缺點也很明顯,應用程序想要進行任何線程操做都須要進行系統調用,應用程序會在用戶態和內核態之間來回切換,消耗的性能資源較多.

  • 使用用戶線程實現: 這種方式將線程徹底實如今用戶空間中,相關的線程操做都在用戶態中完成,這樣能夠避免切換到內核態,提升了性能.但正由於沒有藉助系統調用,操做系統只負責對進程分配資源,這些複雜的線程操做與線程調度都須要由用戶線程本身處理實現,提升了程序的複雜性.這種實現方式下,一個進程對應多個用戶線程,它們是1:N的關係.

  • 混合實現: 這是一種將內核線程與用戶線程一塊兒使用的實現方式.在這種實現下,即存在用戶線程,也存在輕量級進程.用戶線程依舊是在用戶空間中創建的(相關的線程操做也都是在用戶空間中),但使用了輕量級進程來看成用戶線程與內核線程之間的橋樑,讓內核線程提供線程調度和對處理器的映射.這種實現方式下,用戶線程與輕量級進程的數量比例是不定的,它們是N:M的關係.

文件


文件也是一個很是重要的抽象概念,它嚮應用程序提供了一個統一的視圖,來看待系統中可能含有的全部各式各樣的I/O設備.計算機文件系統經過文件與樹形目錄的抽象概念來屏蔽磁盤等物理設備所使用的數據塊(chunk),讓用戶在使用文件的時候無需關心它實際的物理地址,用戶也不須要管理磁盤上的空間分配,這些都由文件系統負責.

所謂文件其實也就是一串字節序列,一個文件想要長期存儲,就必需要存放於某種存儲設備上,如本地磁盤、U盤.

網絡


若是用圖論的方式來看待網絡,其實網絡就是一張無向圖(須要雙向通訊),每臺計算機都是圖中的一個節點(指計算機網絡),圖的邊就是計算機之間互相通訊的鏈接.簡單的說,計算機網絡其實就是多臺計算機進行通訊的系統.

網絡其實也能夠看做是一個I/O設備,當系統從內存中複製一串字節到網絡適配器時,數據流通過網絡傳輸到達另外一臺機器上(這其實就是輸出操做),系統也能夠讀取從其餘機器傳輸過來的數據,並把數據複製到內存中(輸入).

互聯網(Internet)是計算機網絡中的一種(若是按區域劃分還有局域網、廣域網等),互聯網是網絡與網絡之間組成的巨大的國際網絡,這些網絡之間以TCP/IP協議相連,鏈接了全世界上幾十億的設備.

咱們平常生活中用瀏覽器上網瀏覽網頁,其實使用的是萬維網(World Wide Web),它是運行在互聯網之上提供的一個服務,萬維網是一個基於超文本連接組成的系統,而且經過http協議進行訪問.

OSI模型


OSI模型全稱爲開放式系統互聯通訊參考模型(Open System Interconnection Reference Model),是由國際標準化組織提出的一個試圖使各類計算機在世界範圍內進行互聯通訊的標準框架.

OSI模型中,數據通過每一層都會添加該層的協議頭(物理層除外),當一個數據從一端發送到另外一端時,須要通過層層封裝.

  • 應用層: 應用層直接和應用程序通訊並提供常見的網絡應用服務.常見的應用層協議有:HTTP,HTTPS,FTP,TELNET,SSH,SMTP,POP3等.

  • 表示層: 表示層爲不一樣終端的上層用戶提供數據和信息正確的語法表示變換方法.該層定義了數據格式及加解密,

  • 會話層: 會話層負責在數據傳輸中設置和維護網絡中兩臺電腦之間的通訊鏈接.但會話層不參與具體的傳輸,它只提供包括訪問驗證和會話管理在內的創建和維護應用之間通訊的機制.

  • 傳輸層: 傳輸層將數據封裝成數據包,提供端對端的數據通訊服務.它還提供面向鏈接的數據流支持、可靠性、流量控制、多路複用等服務.最著名的傳輸層協議有TCPUDP.

  • 網絡層: 網絡層提供路由和尋址的功能,使兩終端系統可以互連且決定最佳路徑,並具備必定的擁塞控制和流量控制的能力.網絡層將網絡表頭(包含網絡地址等數據)加到數據包中,網絡層協議中最出名的就是IP協議.

  • 數據鏈路層: 數據鏈路層在兩個網絡實體之間提供數據鏈路鏈接的建立、維持和釋放管理.它將數據劃分爲數據幀從一個節點傳輸到臨近的另外一個節點,這些節點是經過MAC(主機的物理地址)來進行標識的.

  • 物理層: 物理層是OSI模型中最低的一層,物理層主要負責傳輸數據所須要的物理鏈路建立、維持、拆除,而提供具備機械的,電子的,功能的和規範的特性.簡單來講,物理層負責了物理設備之間的通訊傳輸.

TCP/IP


TCP協議全稱爲傳輸控制協議(Transmission Control Protocol),因爲它是基於IP協議之上的,因此也有人稱做爲TCP/IP協議.

TCP協議是位於傳輸層的協議,它與一樣位於傳輸層的UDP協議差異很大,它保證了數據包在傳輸時的安全性(丟包重傳),而UDP則只負責發送數據,不保證數據的安全.

TCP爲了保證不發生丟包,給每一個包標記了一個序號,同時序號也保證了接收端在接收數據包時的順序.而後接收端對已成功收到的包發回一個相應的確認(ACK);若是發送端在合理的往返時延(RTT)內未收到確認,那麼對應的數據包就被假設爲已丟失將會被進行重傳.TCP用一個校驗和函數來檢驗數據是否有錯誤,在發送和接收時都要計算校驗和.

TCP協議在鏈接創建與終止時須要通過三次握手與四次揮手,這個機制主要都是爲了提升可靠性.

三次握手
三次握手

  1. 客戶端發送SYN(SEQ=x)報文給服務器端,進入SYN_SEND狀態,等待服務器端確認.

  2. 服務器端收到SYN報文,迴應一個SYN (SEQ=y)ACK(ACK=x+1)報文,進入SYN_RECV狀態.

  3. 客戶端收到服務器端的SYN報文,迴應一個ACK(ACK=y+1)報文,進入Established狀態.

  4. 服務器接收到客戶端發送的SYN報文,三次握手完成,鏈接創建.

四次揮手
四次揮手

  1. 某一端首先調用close,稱該端執行「主動關閉」(active close).該端發送一個FIN報文,表示數據發送完畢(咱們稱它爲A端).

  2. 另外一端接收到這個FIN信號執行 「被動關閉」(passive close ),並回應一個ACK報文.(咱們稱它爲B端)

  3. 一段時間後,B端沒有數據發送的任務了,這時它將調用close關閉套接字,而後向A端發送一個FIN信號.

  4. A端接收到FIN信號,開始進行關閉鏈接,並對B端返回一個ACK.

  5. B端接收到來自A端的ACK信號,進行關閉鏈接,四次揮手完畢.

TCP/IPOSI模型抽象成了四層,下圖爲以HTTP爲例的一個數據發送過程.

分組交換


數據包在網絡中進行傳輸時使用了分組交換.分組交換也稱爲包交換,它將用戶通訊的數據劃分紅多個更小的等長數據段,在每一個數據段的前面加上必要的控制信息做爲數據段的首部,每一個帶有首部的數據段就構成了一個分組.首部指明瞭該分組發送的地址,當交換機收到分組以後,將根據首部中的地址信息將分組轉發到目的地,這個過程就是分組交換.可以進行分組交換的通訊網被稱爲分組交換網.

分組交換的本質就是存儲轉發,它將所接受的分組暫時存儲下來,在目的方向路由上排隊,當它能夠發送信息時,再將信息發送到相應的路由上,完成轉發.其存儲轉發的過程就是分組交換的過程.

數據的表示


計算機編程語言擁有多種數據類型, 例如intchardouble等.但無論是什麼類型的數據,在計算機中其實都只是一個字節序列(以8位二進制爲一個字節).每一個機器中對字節序列的排序不大相同,有一些機器按照從最高有效字節到最低有效字節的順序存儲,這種規則被稱爲大端法;還有一些機器將最低有效字節排在最前面,這種規則被稱爲小端法.

計算機使用補碼來表示數值,一個數的最高有效位爲符號位(以整數爲例,整數佔有4字節32位,最高位即最左位,剩下31位用於表示數字,因此整數的有效範圍爲-2^31 ~ 2^31 - 1),若是符號位爲1,則表明這個值爲負,若是符號位爲0,則表明這個值爲正.負數的補碼便是它的反碼(在保持符號位不變的前提下按位取反)+1,正數的補碼不須要作其餘操做,就是它自己的值.

當將一個較小類型的值強轉爲較大類型時(如byte強轉爲int),將會發生符號擴展,較小類型不包含的位會以符號位來進行填充(仍是以byte爲例,當它強轉爲int時,高24位會被填充爲最高有效位中的數值,若是最高有效位爲1,那麼高24位都會爲1,這時byte原來要表示的值將產生變化,要避免這種狀況,可使用一個低8位爲1高24位爲0的數,將它與強轉後的結果進行&操做,來保留低8位,並消除高24位中的1).

對一個數進行移位操做時,也須要按規則填充丟失的位數.移位操做分爲算術移位與邏輯移位,算術移位會填充符號位,而邏輯移位所有填充0.

  • 當進行左移操做時,右邊空出的位用0補充,高位左移溢出則捨棄該高位.

  • 當進行右移操做時,左邊空出的位用符號位來補充(正數補0,負數補1),右邊溢出則捨棄.若是使用邏輯移位(Java中爲>>>),左邊空出的位會用0來補充.

讀到這裏,可能有人會有疑問,爲何計算機非得使用補碼?這主要由於,計算機中沒有減法器只有加法器,而減去一個數其實就是加上一個負數,使用補碼進行計算會很方便快速.

咱們假設一個指定n爲長度的二進制序列,那麼它將會有2^n個可能的值,加減法運算都存在上溢出與下溢出的狀況,實際上都等價於模(≡) 2^n的加減法運算.

把範圍想象成一個時鐘,假設如今時針指向數字3,若要得出6小時前時針指向的數字是幾,有兩種方法:

  1. 將時針逆時針撥動6格.

  2. 將時針順時針撥動12 - 6 = 6格.

這裏的12就是模,3小時-6小時 = 3小時 + (12 - 6)小時.

例如如下例子,模爲2^8 = 256

  • 一個8位無符號整數的值的範圍是0到255.所以4+254將上溢出,結果爲2: (4 + 254) ≡ 258 ≡ 258 - 256 ≡ 2

  • 一個8位有符號整數的值的範圍是−128到127,則126+125將上溢出,結果爲-5: (126+125) ≡ 251 ≡ 251 - 256 ≡ -5

浮點數


浮點數是一種對於實數的近似值數值表現法,由一個有效數字(即尾數)加上冪數來表示,一般是乘以某個基數的整數次指數獲得.但浮點數計算一般伴隨着由於沒法精確表示而進行的近似或舍入.

在計算機使用的浮點數被電氣電子工程師協會(IEEE)規範化爲IEEE-754,任意一個二進制浮點數V均可以表示成下列形式:

  • V = (-1)^s * M * 2^E

  • (-1)^s表示符號位,當s=0,V爲正數;s=1,V爲負數.

  • M 表示有效數字,1≤M<2.

  • 2^E表示指數位.

這種表示方式有點相似於科學計數法,在計算機中,一般使用2爲基數的冪數來表示.IEEE-754同時還規定了單精度(float)與雙精度(double)的區別:

  • 32位的單精度浮點數,最高1位是符號位s,接着的8位是指數E,剩下的23位是有效數字M.

  • 64位的雙精度浮點數,最高1位是符號位s,接着的11位是指數E,剩下的52位爲有效數字M.

函數調用


當調用一個函數時,系統會在棧上分配一個空間,存放了函數中的局部變量、函數參數、返回地址等,這樣的一個結構被稱爲棧幀.

函數中的數據的存活狀態是後進先出的,而棧正好是知足這一特性的數據結構,這也是爲何計算機使用棧來看成函數調用的存儲結構.

int main() {
  sayHello();
  return 0;
}

void sayHello() {
  hello_world();
}

void hello_world() {
  print("Hello,World");
}


 main()  sayHello()  hello_world()  print()
   -                                main()
   |
   +>     -                            sayHello()
   .      |
   .      +>   -                              hello_world()
   .      .    |
   .      .    +>   -                                  print()
   .      .    .    |
   .      .    +   <-                       return from print()
   .      .    |
   .      +   <-                        return from hello_world()
   .      |
   +     <-                        return from sayHello()
   |
   -                             return from main()複製代碼

x86-64架構中,棧是向低地址方向生長的,寄存器%rsp指向棧頂,當一個函數被調用時,將會執行pushq指令,棧幀入棧,棧指針減少(向下生長),當函數返回後,將會執行popq指令,棧幀出棧,釋放空間,棧指針增長.若是不斷有函數進行調用,棧就會不斷向下生長,最終會產生Stack Overflow.

計算機編程語言


計算機編程語言是用來定義計算機程序的語言,它以一種標準化的語法規則來向計算機發出指令.最先的編程語言是在計算機發明以前產生的,當時是用來控制提花織布機及自動演奏鋼琴的動做.現在已經有上千種不一樣的編程語言,無論是哪一種語言,儘管它們的特性各有不一樣,但寫程序的核心都是條件判斷、循環、分支(這些也是機器指令的核心).

編程語言依賴於編譯器或解釋器(因此也分爲編譯型語言與解釋型語言),若是沒有對應的編譯器/解釋器來對語法與語義進行分析並生成對應的機器語言,那麼咱們所寫的代碼其實都只是普通的文本字符(編譯器/解釋器也會對源代碼進行一系列優化提升性能).

編譯型語言經過編譯器直接將源代碼翻譯成機器語言並生成一個可執行文件(機器語言是不兼容的,若是要到另外一臺機器上運行,就須要對源代碼從新編譯);解釋型語言經過解釋器動態地翻譯源代碼並直接執行(性能上會比編譯型語言直接運行可執行文件要差);雖然大多數的語言既可被編譯又可被解譯,但大多數僅在一種狀況下可以良好運行.

Java的編譯機制比較特殊,它將Java源代碼編譯成JVM字節碼(經過虛擬機來達到一次編譯在全部平臺可用),而後JVM對字節碼進行解釋執行,但對於較熱的代碼塊(頻繁調用的函數等),JVM會經過JIT即時編譯技術將這些頻繁使用的代碼塊動態地編譯成機器語言,提升程序的性能.

相關文章
相關標籤/搜索