溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

hello程序是如何運(yùn)行的

發(fā)布時(shí)間:2022-01-05 09:51:41 來(lái)源:億速云 閱讀:225 作者:iii 欄目:云計(jì)算

這篇文章主要介紹“hello程序是如何運(yùn)行的”,在日常操作中,相信很多人在hello程序是如何運(yùn)行的問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”hello程序是如何運(yùn)行的”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

在開(kāi)始之前,我們先看一個(gè)最常見(jiàn)的程序:

#include <stdio.h>
int main()
{
    printf("hello,world\n");
    return 0;
}

本文就從上面這個(gè)最簡(jiǎn)單的hello程序展開(kāi),沿著它的生命周期展開(kāi)學(xué)習(xí).

程序的保存格式

上面的hello程序其實(shí)就是一個(gè)由值 0 和 1 組成的位(即比特)序列,8個(gè)位成一組,稱(chēng)為字節(jié)。我們輸入文本hello.c文件中的字符即用每個(gè)字節(jié)來(lái)表示(大部分計(jì)算機(jī)系統(tǒng)都是用ASCII標(biāo)準(zhǔn)來(lái)表示字符,即把字節(jié)轉(zhuǎn)為整數(shù)值)。

總結(jié): 信息=位+上下文

程序是如何運(yùn)行的

hello程序的誕生使用C語(yǔ)言來(lái)編寫(xiě)的,好處是人可以讀懂,但是為了在系統(tǒng)上運(yùn)行,還是得轉(zhuǎn)化為一系列低級(jí)的機(jī)器語(yǔ)言指令。

在Unix系統(tǒng)上,從源文件到目標(biāo)文件的轉(zhuǎn)化得靠編譯器, 下面記錄編譯過(guò)程:

hello程序是如何運(yùn)行的

  1. hello.c需要經(jīng)過(guò)預(yù)處理器讀取系統(tǒng)頭文件內(nèi)容并且插入到程序文本中得到一個(gè)新的C程序,一般以.i作為擴(kuò)展名;

  2. 然后編譯器將文本文件hello.i 翻譯成匯編語(yǔ)言文本文件hello.s

  3. 接下來(lái),就該匯編器登場(chǎng),將匯編語(yǔ)言翻譯成機(jī)器語(yǔ)言指令,并保存到hello.o文件中,此時(shí)它是一個(gè)二進(jìn)制文件了

  4. 最后鏈接階段,將程序中調(diào)用的c標(biāo)準(zhǔn)庫(kù)的函數(shù)合并到我們的hello.o程序中,結(jié)果就是一個(gè)可執(zhí)行文件,可以被加載到內(nèi)存中,由系統(tǒng)執(zhí)行。

系統(tǒng)的硬件組成

要真正了解程序時(shí)如何運(yùn)行的,首先要對(duì)系統(tǒng)的硬件組成有一個(gè)了解:

  1. 總線(xiàn):貫穿整個(gè)系統(tǒng)的電子管道,可以理解為所有的數(shù)據(jù)設(shè)備以及系統(tǒng)之間的數(shù)據(jù)流轉(zhuǎn)都要接到總線(xiàn)上。

  2. I/O設(shè)備:系統(tǒng)與外部世界的聯(lián)系通道;比如鍵盤(pán)、鼠標(biāo)、磁盤(pán)、顯示器等;

    所有的I/O設(shè)置都要通過(guò)一個(gè)控制器或者適配器與I/O總線(xiàn)相連;

  3. 主存:也就是我們常說(shuō)的內(nèi)存,這是一個(gè)臨時(shí)存儲(chǔ)設(shè)備,在處理器執(zhí)行程序時(shí),用來(lái)存放程序和處理的數(shù)據(jù);

  4. 處理器:也就是我們常說(shuō)的CPU,是解釋存儲(chǔ)在主存中指令的引擎;其核心是一個(gè)大小為一個(gè)字(定長(zhǎng)的字節(jié),根據(jù)系統(tǒng)不同確定)的寄存器,稱(chēng)為程序計(jì)數(shù)器(PC)。在程序運(yùn)行的過(guò)程中,PC都是指向主存中的一條機(jī)器語(yǔ)言指令。

    從系統(tǒng)通電開(kāi)始,直到系統(tǒng)斷電,處理器一直在不斷的執(zhí)行PC指向的指令,在更新PC,使其指向下一條指令;

    下面列舉幾個(gè)CPU在指令要求下可能執(zhí)行的操作:

    處理器看上去是它的指令集架構(gòu)的簡(jiǎn)單實(shí)現(xiàn),但是現(xiàn)代處理器采用非常復(fù)雜的機(jī)制來(lái)加速程序的運(yùn)行。因此我們?cè)诶斫獾臅r(shí)候要將處理器的指令集架構(gòu) 和處理器的 微體系結(jié)構(gòu)分來(lái):指令集架構(gòu)描述的是每條機(jī)器代碼指令的效果;微體系結(jié)構(gòu)描述的是處理器的實(shí)現(xiàn);

    • 加載:從主存復(fù)制一個(gè)字到寄存器,已覆蓋原有寄存器的內(nèi)容;

    • 存儲(chǔ):從寄存器復(fù)制一個(gè)字到主存的某個(gè)位置,以覆蓋這個(gè)位置的原有值;

    • 操作:把兩個(gè)寄存器的內(nèi)容復(fù)制到ALU(算數(shù)/邏輯單元),ALU對(duì)這兩個(gè)字做算數(shù)運(yùn)算,并將結(jié)果存放到一個(gè)寄存器中覆蓋原有的內(nèi)容;

    • 跳轉(zhuǎn):從指令本身抽取一個(gè)字,并將這個(gè)字復(fù)制到PC中,以覆蓋PC中原來(lái)的值;

運(yùn)行程序

當(dāng)我們?cè)趫?zhí)行 ./hello 后,其實(shí)發(fā)生的過(guò)程是:

剛開(kāi)始,shell程序執(zhí)行它的指令,等待我們輸入一個(gè)命令,當(dāng)我們輸入./hello 后,shell程序?qū)⒆址x入寄存器,在把它存放到內(nèi)存中;

當(dāng)你在敲回車(chē)時(shí),shell程序就知道我們已經(jīng)結(jié)束了命令的輸入,然后shell執(zhí)行一系列指令來(lái)加載可執(zhí)行文件,將目前文件的代碼和數(shù)據(jù)復(fù)制到主存。注:利用直接存儲(chǔ)器(DMA)技術(shù),數(shù)據(jù)可以不到處理器直接從磁盤(pán)到主存。

一旦加載到內(nèi)存中,處理器就開(kāi)始執(zhí)行程序的main機(jī)器指令,這些指令將“hello,world\n” 字符串中字節(jié)從主存復(fù)制到寄存器文件。再?gòu)募拇嫫魑募?fù)制到顯示設(shè)備,最終展示在屏幕上。

hello程序是如何運(yùn)行的

高速緩存

從上面的例子,我們可以總結(jié)出,hello程序經(jīng)歷了從開(kāi)始在磁盤(pán)上,加載時(shí)被復(fù)制到主存,處理器運(yùn)行時(shí)又從主存復(fù)制到處理器,最后又從處理器復(fù)制到顯示器。

這里從我們程序員角度講,這些復(fù)制就是開(kāi)銷(xiāo),那么問(wèn)題來(lái)了,如何減小開(kāi)銷(xiāo)提高處理器效率呢???

從機(jī)械原理角度來(lái)看,存儲(chǔ)設(shè)備越大運(yùn)行越慢;處理器讀磁盤(pán)比讀內(nèi)存開(kāi)銷(xiāo)大1000萬(wàn)倍,而寄存器文件的讀取速度又比內(nèi)存塊幾乎100倍,加快處理器的運(yùn)行速度比加快主存運(yùn)行速度要容器的多。

針對(duì)處理器與主存之間的差異,系統(tǒng)設(shè)計(jì)采用了更小更快的存儲(chǔ)設(shè)備,稱(chēng)之為高速緩存,存放處理器近期可能會(huì)需要的信息。這個(gè)其實(shí)和我們平時(shí)開(kāi)發(fā)程序是一樣的,采用多級(jí)緩存,存放熱點(diǎn)數(shù)據(jù),提高系統(tǒng)處理能力。 這里的原理是利用程序具有訪(fǎng)問(wèn)局部區(qū)域里的數(shù)據(jù)和代碼的趨勢(shì),所以高速緩存中存放了可能經(jīng)常訪(fǎng)問(wèn)的數(shù)據(jù),這樣大部分操作就能在告訴緩存中完成。

請(qǐng)看下面的存儲(chǔ)器層次的結(jié)構(gòu),相信你會(huì)一目了然:

hello程序是如何運(yùn)行的

如圖所示,上一層存儲(chǔ)器是下一層的高速緩存。

操作系統(tǒng)管理硬件

我們寫(xiě)的程序,沒(méi)有直接訪(fǎng)問(wèn)鍵盤(pán)、顯示器、磁盤(pán)等硬件,而是依賴(lài)操作系統(tǒng)提供的服務(wù),所以可以把操作系統(tǒng)看成是應(yīng)用程序和硬件之間一層軟件。

hello程序是如何運(yùn)行的

操作系統(tǒng)有兩大功能:

  1. 防止硬件被濫用;

  2. 對(duì)應(yīng)用程序屏蔽底層復(fù)雜而通常又大不相同的硬件設(shè)備,提供簡(jiǎn)單一致的機(jī)制;

操作系統(tǒng)通常抽象出幾個(gè)概念:進(jìn)程、虛擬內(nèi)存、文件;

進(jìn)程

進(jìn)程是操作系統(tǒng)對(duì)一個(gè)正在運(yùn)行的應(yīng)用程序的抽象,一個(gè)系統(tǒng)可以同時(shí)運(yùn)行多個(gè)進(jìn)程。

單核處理器一個(gè)時(shí)刻只能執(zhí)行一個(gè)程序,而目前的多核處理器能同時(shí)執(zhí)行多個(gè)程序。無(wú)論單核還是多核,一個(gè)CPU看上去都是在并發(fā)執(zhí)行多個(gè)進(jìn)程,這是通過(guò)處理器在進(jìn)程間切換來(lái)實(shí)現(xiàn)的,這種切換被稱(chēng)為 上下文切換;

進(jìn)程之間的切換是由操作系統(tǒng)內(nèi)核管理的,內(nèi)核是操作系統(tǒng)常駐主存的部分。當(dāng)應(yīng)用程序需要操作系統(tǒng)的某些操作時(shí),比如讀寫(xiě)文件,它就執(zhí)行一條系統(tǒng)調(diào)用指令,將控制權(quán)傳遞給內(nèi)核。然后內(nèi)核執(zhí)行被請(qǐng)求的操作并返回應(yīng)用程序。 注意,內(nèi)核不是一個(gè)獨(dú)立的進(jìn)程,它是系統(tǒng)管理所有進(jìn)程所用代碼和數(shù)據(jù)結(jié)構(gòu)的集合。

線(xiàn)程

一個(gè)進(jìn)程實(shí)際上是由多個(gè)稱(chēng)為線(xiàn)程的執(zhí)行單元組成,每個(gè)線(xiàn)程都運(yùn)行在進(jìn)程的上下文中,并共享同樣的代碼和全局?jǐn)?shù)據(jù)。

優(yōu)點(diǎn):比進(jìn)程之間更容易共享數(shù)據(jù);一般來(lái)講也比進(jìn)程更高效;

虛擬內(nèi)存

這是一個(gè)抽象概念,它為每個(gè)進(jìn)程提供了一個(gè)假象,即每個(gè)進(jìn)程都在單獨(dú)使用主存,每個(gè)進(jìn)程看到的內(nèi)存都是一致的,稱(chēng)為虛擬地址空間,如下圖所示,地址是從小往上增大的:

hello程序是如何運(yùn)行的

文件

文件就是字節(jié)序列,所有的I/O設(shè)備,甚至網(wǎng)絡(luò)都可以看成是文件;

并發(fā)

多核處理器是將多個(gè)CPU集成到一個(gè)集成電路芯片上。多核處理器組織架構(gòu)如下:

hello程序是如何運(yùn)行的

超線(xiàn)程:稱(chēng)為同時(shí)多線(xiàn)程,允許一個(gè)CPU同時(shí)執(zhí)行多個(gè)并發(fā)流的技術(shù)。Intel Core i7 處理器可以讓每個(gè)核執(zhí)行兩個(gè)線(xiàn)程。

計(jì)算機(jī)系統(tǒng)中的抽象

在處理里,指令集架構(gòu)提供了對(duì)實(shí)際處理器硬件的抽象,使用這個(gè)抽象,機(jī)器代碼表現(xiàn)的好像運(yùn)行在一個(gè)一次只執(zhí)行一條指令的處理器上。不管底層多復(fù)雜精細(xì),哪怕可以并發(fā)的執(zhí)行多條指令,擔(dān)又總是與那個(gè)簡(jiǎn)單有序的模型保持一致。只要模型一樣,不同的處理器實(shí)現(xiàn)也能執(zhí)行同樣的機(jī)器代碼,而又提供不同的開(kāi)銷(xiāo)和性能。這種抽象思想簡(jiǎn)直太重要了,在整個(gè)計(jì)算機(jī)科學(xué)中也隨處可見(jiàn),比如java類(lèi)的生命和C語(yǔ)言的函數(shù)原型,以及計(jì)算機(jī)網(wǎng)絡(luò)的分層。

hello程序是如何運(yùn)行的

看了上面這副圖可以總結(jié)為:

  1. 文件是對(duì)I/O設(shè)置的抽象;

  2. 虛擬內(nèi)存是對(duì)主存和磁盤(pán)的抽象;

  3. 進(jìn)程是對(duì)處理器、主存和I/O設(shè)備的抽象;

至此,本章的學(xué)習(xí)就結(jié)束了,主要對(duì)計(jì)算機(jī)系統(tǒng)的組成和程序運(yùn)行有了大框架的認(rèn)知,后續(xù)繼續(xù)進(jìn)行深入學(xué)習(xí)。

擴(kuò)展問(wèn)題

  1. 信息=位+上下文,什么是上下文?工作中有哪些例子?

每一段程序都有很多外部變量。只有像Add這種簡(jiǎn)單的函數(shù)才是沒(méi)有外部變量的。一旦你的一段程序有了外部變量,這段程序就不完整,不能獨(dú)立運(yùn)行。你為了使他們運(yùn)行,就要給所有的外部變量一個(gè)一個(gè)寫(xiě)一些值進(jìn)去。這些值的集合就叫上下文。 比如:C++的lambda表達(dá)式里面,[寫(xiě)在這里的就是上下文](int a, int b){ ... }

  1. RISC指令集和CISC指令集有什么區(qū)別,它們的典型CPU有哪些?

  • CSIC(Complex Instruction Set Computer) 復(fù)雜指令集的CPU; CISC體系的設(shè)計(jì)理念是用最少的指令來(lái)完成任務(wù)(譬如計(jì)算乘法只需要一條MUL指令即可),因此CISC的CPU本身設(shè)計(jì)復(fù)雜、工藝復(fù)雜,但好處是編譯器好設(shè)計(jì)。CISC出現(xiàn)較早,至今Intel還一直采用CISC設(shè)計(jì);

  • RSIC(Reduced Instruction Set Computer) 精簡(jiǎn)指令集的CPU; RISC的設(shè)計(jì)理念是讓軟件來(lái)完成具體的任務(wù),CPU本身僅提供基本功能指令集,即:指令集中指令的數(shù)量相對(duì)很少。這種設(shè)計(jì)理念相對(duì)于CISC的設(shè)計(jì)理念,CPU的設(shè)計(jì)和工藝簡(jiǎn)單了,但是編譯器的設(shè)計(jì)變復(fù)雜了

  • 典型CPU: 一般典型CISC的CPU指令數(shù)在300條左右。ARM的CPU(作為典型的RISC的CPU)常用指令數(shù)在30條左右。 一般來(lái)說(shuō),CISC的CPU的功耗更高,一般用在PC機(jī)和筆記本電腦中。相對(duì)來(lái)說(shuō),RISC的CPU的功耗更低,一般用在嵌入式領(lǐng)域。

  1. 基于棧的CPU和基于寄存器的CPU有什么區(qū)別?

這個(gè)問(wèn)題可以將JVM看成是一個(gè)基于棧的CPU,它在運(yùn)行程序的時(shí)候都是用棧,代碼必須使用這些指令來(lái)移動(dòng)變量(即push和pop);

到此,關(guān)于“hello程序是如何運(yùn)行的”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI