新聞中心
寫程序離不開運(yùn)行時,但是有很多伙伴卻并沒有搞清楚運(yùn)行時到底是什么。運(yùn)行時的概念之所以容易被混淆,是因為運(yùn)行時有兩層不同的含義:run time 和 runtime,先賢們在翻譯的時候可能忽略了中間的空格,導(dǎo)致運(yùn)行時一詞代表了兩種含義:運(yùn)行時期和運(yùn)行環(huán)境/系統(tǒng)。

創(chuàng)新互聯(lián)專注于恩平網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗。 熱誠為您提供恩平營銷型網(wǎng)站建設(shè),恩平網(wǎng)站制作、恩平網(wǎng)頁設(shè)計、恩平網(wǎng)站官網(wǎng)定制、小程序定制開發(fā)服務(wù),打造恩平網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供恩平網(wǎng)站排名全網(wǎng)營銷落地服務(wù)。
運(yùn)行時期(Run time)在計算機(jī)科學(xué)中代表一個程序從開始執(zhí)行到終止執(zhí)行的運(yùn)作時期,與之相對的其他時期包括:設(shè)計時期(design time)、編譯時期(compile time)、鏈接時期(link time)與載入時期(load time)。
runtime 是一個通用抽象的術(shù)語,指的是計算機(jī)程序運(yùn)行的時候所需要的一切代碼庫,框架,平臺等。它包括了程序的執(zhí)行環(huán)境和執(zhí)行狀態(tài),以及程序在運(yùn)行時所產(chǎn)生的各種數(shù)據(jù)和結(jié)果。runtime主要是為了實現(xiàn)程序設(shè)計語言的執(zhí)行模型,在每種語言有著不同的實現(xiàn)。runtime的概念在編程中非常重要,它關(guān)系到程序的正確性、穩(wěn)定性和性能等方面。
run time 和 runtime 就有區(qū)別又有聯(lián)系,都是軟件設(shè)計的基礎(chǔ)。run time 是從程序自身的視角來看的,而runtime 則是從程序的執(zhí)行環(huán)境和依賴的視角來看的。因此,在我們討論運(yùn)行時的時候,一定要明確上下文,才能理解運(yùn)行時的真正含義,并通過運(yùn)行時的相關(guān)技術(shù)讓我們的軟件系統(tǒng)更加靈活可靠。
運(yùn)行時:run time——運(yùn)行時期
運(yùn)行時期(run time)是程序生命周期的一個階段,是代碼在執(zhí)行時的行為。編譯時期(compile time)是指程序設(shè)計中,編譯器在編譯源代碼時的行為,包括語法分析、語義分析、類型檢查、模板實例化、代碼生成等。編程語言通常會指出源程序必須滿足的編譯時期要求。有些編程語言在鏈接時期或運(yùn)行時期才執(zhí)行一部分編譯,例如即時編譯(Just-in-time compilation)。
程序執(zhí)行中的某些問題只能在運(yùn)行時期才能進(jìn)行檢測,例如邏輯錯誤或數(shù)組邊界檢查等。因此,用戶也會遇到諸如運(yùn)行時錯誤之類的信息。
運(yùn)行時期的驗證
運(yùn)行時驗證是一種輕量級的驗證技術(shù)。它是傳統(tǒng)驗證技術(shù),是模型檢測和測試的一個有效補(bǔ)充。它最重要的一個特征是其驗證對象為被監(jiān)控系統(tǒng)的實際運(yùn)行,從而使得檢測到錯誤時能及時采取相應(yīng)的調(diào)整行為,以達(dá)到避免軟件失效發(fā)生或阻止軟件失效進(jìn)一步傳播的目的。
運(yùn)行時驗證關(guān)注于檢測程序的運(yùn)行軌跡是否滿足或違背監(jiān)控的性質(zhì)。當(dāng)程序的運(yùn)行滿足或違背監(jiān)控性質(zhì)時,運(yùn)行時驗證技術(shù)一般不會對被監(jiān)控的系統(tǒng)進(jìn)行調(diào)整。也就是說,運(yùn)行時驗證技術(shù)是關(guān)于程序運(yùn)行軌跡是否滿足監(jiān)控性質(zhì)的判別技術(shù)。基于AOP的監(jiān)控器具有高效(不需要進(jìn)行環(huán)境切換)、容易部署(不涉及到對虛擬機(jī)和操作系統(tǒng)的修改)和準(zhǔn)確(基于AOP的監(jiān)控器能夠獲取被監(jiān)控程序更多的狀態(tài)信息)的特點。
程序在編譯時期和運(yùn)行時間的不同體現(xiàn)
這里以多態(tài)為例來描述一下程序特性在編譯時期和運(yùn)行時間的不同體現(xiàn)。
先簡要澄清一下多態(tài)。多態(tài)指同一個實體同時具有多種形式,是面向?qū)ο蟪绦蛟O(shè)計(OOP)的一個重要特征。也就是說,同一操作作用于不同的對象,可以有不同的解釋,產(chǎn)生不同的執(zhí)行結(jié)果。在運(yùn)行時,可以通過指向基類的指針,來調(diào)用實現(xiàn)派生類中的方法。如果一個語言只支持類而不支持多態(tài),只能說明它是基于對象的,而不面向?qū)ο蟮摹?/p>
多態(tài)分為兩種情況:編譯時多態(tài)與運(yùn)行時多態(tài)。編譯時多態(tài)即在編譯時就能夠確定調(diào)用哪個方法。而運(yùn)行時多態(tài)則相反,只有在運(yùn)行時才能確定調(diào)用哪個方法。在方法重載時,都是編譯時多態(tài)。在編譯期可根據(jù)參數(shù)的數(shù)據(jù)類型、個數(shù)以及次序來確定調(diào)用方法。當(dāng)子類對象引用自身類實例方法時,也為編譯時多態(tài)。但是當(dāng)父類對象引用子類實例方法時,是運(yùn)行時多態(tài),因為此時只有在運(yùn)行時才可以去匹配到對應(yīng)方法進(jìn)行調(diào)用。
運(yùn)行時期的軟件配置
運(yùn)行時期的軟件配置是軟件配置的一種形式,增加了軟件系統(tǒng)的靈活性和適應(yīng)性。
軟件配置可以分為運(yùn)行時期配置(run time configuration) 和編譯時配置 (compile time configuration). 運(yùn)行時配置是軟件的重要接口, 可以定制不同的功能、管理資源的分配、適應(yīng)環(huán)境的變化以及滿足不同用戶的需求, 主要面向軟件管理員和用戶, 無需重新編譯部署即可實現(xiàn)軟件調(diào)整. 而編譯時配置也稱軟件生產(chǎn)線配置(software product line configuration, SPL configuration),主要用于軟件構(gòu)建和部署時期決定特定功能模塊是否加入可執(zhí)行程序中, 以此決定軟件的最終形態(tài), 主要面向軟件開發(fā)和部署人員, 必須重新編譯才能使用。
運(yùn)行時期的編譯優(yōu)化
一般地,軟件的優(yōu)化技術(shù)分成兩類:靜態(tài)優(yōu)化和動態(tài)優(yōu)化。其中,動態(tài)優(yōu)化目前主要集中在對動態(tài)語言程序如 Java、Ruby、Python 等的優(yōu)化。運(yùn)行時期的軟件優(yōu)化大多通過動態(tài)編譯技術(shù)來實現(xiàn)。
動態(tài)編譯技術(shù)又可以分為兩大類:①選擇性編譯:主要關(guān)注何時選擇程序哪一部分代碼進(jìn)行動態(tài)編譯和優(yōu)化;②基于反饋的優(yōu)化:利用剖析信息來指導(dǎo)動態(tài)編譯器來做何種級別的編譯優(yōu)化。動態(tài)編譯器通常支持兩種執(zhí)行方式:一種是解釋執(zhí)行或無優(yōu)化的編譯器編譯執(zhí)行;一種是優(yōu)化編譯,對熱點路徑進(jìn)行重點優(yōu)化。動態(tài)編譯器中的編譯優(yōu)化工作是在程序運(yùn)行時期中進(jìn)行,編譯開銷包含在程序的運(yùn)行開銷中。
動態(tài)編譯器不僅可以選擇對哪些代碼做編譯或者優(yōu)化編譯,而且還可以在程序的運(yùn)行中采集程序的運(yùn)行信息,主要包括程序的循環(huán)深度、程序輸入以及運(yùn)行環(huán)境(操作系統(tǒng)、體系結(jié)構(gòu))等。利用這些運(yùn)行時信息,動態(tài)編譯器可以更好地決定采用何種編譯優(yōu)化策略對程序進(jìn)行編譯優(yōu)化。動態(tài)剖析技術(shù)使得多級優(yōu)化編譯成為可能,每一級采用特定的優(yōu)化策略,熱點的性
能更容易得到提升,這就是基于反饋的動態(tài)優(yōu)化技術(shù))。
基于反饋的動態(tài)優(yōu)化技術(shù)主要通過對程序插樁,利用插入的代碼收集需要的程序信息,然后將它們按照一定的格式組織起來進(jìn)行分析, 從而指導(dǎo)優(yōu)化器進(jìn)行重編譯。
運(yùn)行時:runtime——運(yùn)行時環(huán)境/運(yùn)行時系統(tǒng)
runtime 或者 run-time是指運(yùn)行環(huán)境,又稱為“運(yùn)行時系統(tǒng)”,簡稱“運(yùn)行時”,是執(zhí)行碼在目標(biāo)機(jī)器上運(yùn)行的環(huán)境。它有可能是由操作系統(tǒng)提供,或由執(zhí)行此程序的父程序提供。通常由操作系統(tǒng)負(fù)責(zé)處理程序的載入:利用加載器(loader)讀入程序執(zhí)行碼,進(jìn)行基本的內(nèi)存配置,并視需要鏈接此程序指定的所有動態(tài)鏈接庫。有些編程語言也會由此語言提供的運(yùn)行環(huán)境處理上述工作。
運(yùn)行環(huán)境可以解決許多問題,包括應(yīng)用程序內(nèi)存的管理、程序如何訪問變量、程序之間傳遞參數(shù)的機(jī)制、與操作系統(tǒng)的接口等問題。編譯器根據(jù)具體的運(yùn)行時系統(tǒng)做出假設(shè),以生成正確的代碼。通常情況下,運(yùn)行時系統(tǒng)將承擔(dān)一些設(shè)置和管理堆棧的責(zé)任,并可能包括諸如垃圾回收、線程或其他內(nèi)置于語言中的動態(tài)功能。
對于很多傳統(tǒng)高級語言尤其是動態(tài)語言而言,?運(yùn)行時系統(tǒng)基本上就是程序和硬件的橋梁。一般地,運(yùn)行時系統(tǒng)實際上提供了一個動態(tài)語言得以執(zhí)行的統(tǒng)一的虛擬計算機(jī),這樣一個虛擬機(jī)完全屏蔽了硬件的具體特征?從而極大的提高了軟件的開發(fā)效率。但是正因為這個虛擬機(jī)完全屏蔽了程序員接觸硬件特性的可能,虛擬機(jī)本身必須承擔(dān)起充分利用硬件特性來高效執(zhí)行動態(tài)語言程序的責(zé)任。
運(yùn)行時模型與運(yùn)行時體系結(jié)構(gòu)
每種語言都有一個特定的執(zhí)行模型(Execution Model),而這個執(zhí)行模型就需要運(yùn)行時系統(tǒng)的支撐。運(yùn)行時系統(tǒng)除了提供程序運(yùn)行機(jī)制之外,一般還提供內(nèi)存管理機(jī)制和并發(fā)機(jī)制。
運(yùn)行時模型是關(guān)聯(lián)系統(tǒng)的因果關(guān)系自述,從問題空間的角度強(qiáng)調(diào)系統(tǒng)的結(jié)構(gòu)、行為或目標(biāo),運(yùn)行時模型提供了運(yùn)行時現(xiàn)象的抽象,利用運(yùn)行時模型能夠修復(fù)設(shè)計錯誤或?qū)⑿碌脑O(shè)計決策折疊到正在運(yùn)行的系統(tǒng)中, 以支持受控的在線設(shè)計。同時,運(yùn)行時模型作為軟件演化和適應(yīng)行為的基礎(chǔ) ,也是解決復(fù)雜系統(tǒng)運(yùn)行時管理問題的關(guān)鍵 。
運(yùn)行時模型分為運(yùn)行時結(jié)構(gòu)模型和運(yùn)行時行為模型。其中, 運(yùn)行時結(jié)構(gòu)模型側(cè)重于描述系統(tǒng)的組成及配置, 即強(qiáng)調(diào)軟件的構(gòu)建方式,如面向?qū)ο蠖?,結(jié)構(gòu)模型描述的是繼承關(guān)系和調(diào)用途徑、組件及其連接 等;運(yùn)行時行為模型側(cè)重于描述組件間動態(tài)交互信息,強(qiáng)調(diào)根據(jù)事件或跟蹤流程的系統(tǒng)執(zhí)行,或者事件的發(fā)生及其執(zhí)行途徑,如行為模型描述事件的到達(dá)、排隊、選擇、調(diào)度等信息。
運(yùn)行時軟件體系結(jié)構(gòu)是控制運(yùn)行時系統(tǒng)復(fù)雜性、輔助系統(tǒng)運(yùn)行時管理的有效途徑.作為系統(tǒng)運(yùn)行時刻的動態(tài)描述,運(yùn)行時體系結(jié)構(gòu)刻畫了系統(tǒng)當(dāng)前時刻的構(gòu)成元素、各元素內(nèi)部的屬性以及元素之間的關(guān)系。運(yùn)行時體系結(jié)構(gòu)與目標(biāo)系統(tǒng)之間具有“因果關(guān)聯(lián)”,即系統(tǒng)發(fā)生變化時,體系結(jié)構(gòu)隨之改變;而體系結(jié)構(gòu)被修改后,系統(tǒng)也將隨之改變,這種動態(tài)的因果關(guān)聯(lián)保證了系統(tǒng)管理者可以通過讀寫體系結(jié)構(gòu)中的元素、屬性以及連接關(guān)系,實現(xiàn)對目標(biāo)系統(tǒng)的監(jiān)測和調(diào)整。運(yùn)行時體系結(jié)構(gòu)抽象了系統(tǒng)的運(yùn)行時數(shù)據(jù),并以符合管理視角的方式對這些數(shù)據(jù)進(jìn)行組織,同時對外提供簡單、一致的操作方式.
運(yùn)行時體系結(jié)構(gòu)與設(shè)計階段體系結(jié)構(gòu)最大的不同在于:運(yùn)行時體系結(jié)構(gòu)與運(yùn)行時系統(tǒng)間存在因果聯(lián)系,而設(shè)計階段體系結(jié)構(gòu)不具備這一屬性。運(yùn)行時體系結(jié)構(gòu)模型側(cè)重如何通過模型來描述運(yùn)行時系統(tǒng)當(dāng)前時刻的結(jié)構(gòu)和配置 。
運(yùn)行時的實現(xiàn)與分類
在編程語言中,runtime通常是由編譯器和運(yùn)行時庫共同實現(xiàn)的。編譯器負(fù)責(zé)將源代碼編譯成可執(zhí)行代碼,而運(yùn)行時庫則負(fù)責(zé)在程序運(yùn)行時提供各種運(yùn)行時支持和服務(wù)。運(yùn)行時庫通常包括了各種系統(tǒng)庫和標(biāo)準(zhǔn)庫,以及一些特定于編程語言的庫和框架。
在C語言中,runtime的實現(xiàn)通常是由C庫和操作系統(tǒng)共同提供的。C庫提供了各種常用的函數(shù)和數(shù)據(jù)類型,而操作系統(tǒng)則提供了一些底層的系統(tǒng)調(diào)用和服務(wù)。在Java語言中,runtime的實現(xiàn)則是由Java虛擬機(jī)(JVM)和Java類庫共同提供的。JVM負(fù)責(zé)將Java字節(jié)碼編譯成可執(zhí)行代碼,并提供各種運(yùn)行時支持和服務(wù),而Java類庫則提供了各種常用的類和函數(shù)。
根據(jù)運(yùn)行時系統(tǒng)實現(xiàn)的不同,可以將運(yùn)行時系統(tǒng)初步分成三類:
第一種是是原生運(yùn)行時,例如C/C++/Rust,這些語言的運(yùn)行時系統(tǒng)是依賴操作系統(tǒng)的,操作系統(tǒng)也可以認(rèn)為是一種“運(yùn)行時環(huán)境”。
第二種是輕運(yùn)行時,例如Golang,它的運(yùn)行時是和代碼打包到一起的,相對輕量一些。
第三種是重運(yùn)行時,例如Java(JVM),Python(CPython),還有 C#(.NET Runtime)。它們的運(yùn)行時環(huán)境是需要單獨安裝的,而且一般還不小,幾十兆上百兆都是正常的。
其中,在C/C++里你可以不引用任何庫,Rust里有一個專門的特性叫 no_std,脫離標(biāo)準(zhǔn)庫提供了一個很牛的能力,就是直接和硬件交互。也就是說,C/C++/Rust是可以用來編寫操作系統(tǒng)內(nèi)核的。
運(yùn)行時庫
運(yùn)行時庫(runtime library),在計算機(jī)程序設(shè)計領(lǐng)域中,是指編程語言程序運(yùn)行時(執(zhí)行)所需要的一種特殊的計算機(jī)程序庫,編譯器會調(diào)用運(yùn)行時庫至已編譯的可執(zhí)行二進(jìn)制代碼中。這種庫一般包括基本的輸入輸出或是內(nèi)存管理等,一般是一群支持正在執(zhí)行程序的函數(shù),與操作系統(tǒng)合作提供諸如數(shù)學(xué)運(yùn)算、輸入輸出等功能,讓開發(fā)者不需要“重新發(fā)明輪子”,并使用操作系統(tǒng)提供的功能。
運(yùn)行時庫提供了程序執(zhí)行時的最基本需要。比如Visual Basic需要復(fù)雜的運(yùn)行時庫支持而C的運(yùn)行時庫則相對簡單。運(yùn)行時庫中的函數(shù)可能對程序員透明,也可能不透明,這是由編譯器廠商根據(jù)語言執(zhí)行環(huán)境的需求而決定的。
許多近代語言設(shè)計了更強(qiáng)大的運(yùn)行時環(huán)境并添加了更多功能,很多面向?qū)ο笳Z言也包含了分派器與類別讀取器,Java虛擬機(jī)(JVM)便是此類的典型執(zhí)行環(huán)境,而.NET架構(gòu)也是另外一個運(yùn)行時庫的實例。異常處理(Exception handling)是專門處理執(zhí)行期錯誤的語言機(jī)制,使開發(fā)者可以完全捕捉非預(yù)期錯誤,或沒有適當(dāng)處理的錯誤結(jié)果。
動態(tài)鏈接庫或靜態(tài)鏈接庫與運(yùn)行時庫的分類角度不同,運(yùn)行時庫就是程序運(yùn)行的時候所需要依賴的庫文件.
C和C++運(yùn)行時庫
為了提高C語言的開發(fā)效率,C標(biāo)準(zhǔn)定義了一系列常用的函數(shù),稱為C庫函數(shù)。C標(biāo)準(zhǔn)僅僅定義了函數(shù)原型,并沒有提供實現(xiàn)。因此這個任務(wù)留給了各個支持C語言標(biāo)準(zhǔn)的編譯器。每個編譯器通常實現(xiàn)了標(biāo)準(zhǔn)C的超集,稱為C運(yùn)行時庫(C Run Time Library),簡稱CRT。C標(biāo)準(zhǔn)庫就是任何平臺都可以使用的基本C語言庫。而CRT除了將C標(biāo)準(zhǔn)庫加入所屬范圍外,還擴(kuò)展了與平臺相關(guān)的接口庫,這些接口實現(xiàn)根據(jù)不同平臺調(diào)用不同平臺的操作系統(tǒng)API。
與C語言類似,C++也定義了自己的標(biāo)準(zhǔn),同時提供相關(guān)支持庫,稱為C++運(yùn)行時庫或C++標(biāo)準(zhǔn)庫。由于C++對C的兼容性,C++標(biāo)準(zhǔn)庫包括了C標(biāo)準(zhǔn)庫,除此之外還包括了IO流和標(biāo)準(zhǔn)模板庫STL。
圖片
VC+按照C和C++標(biāo)準(zhǔn)定義的函數(shù)原型實現(xiàn)了上述運(yùn)行時庫。為了方便有不同需求的客戶使用,VC++分別實現(xiàn)了動態(tài)鏈接庫DLL版本和靜態(tài)鏈接庫LIB版本。同時為了支持程序調(diào)試且不影響程序的性能,又分別提供了對應(yīng)的調(diào)試版本。使用DLL版的C和C++運(yùn)行庫,程序在運(yùn)行時動態(tài)的加載對應(yīng)的DLL。程序體積變小,但一個很大的問題就是一旦找不到對應(yīng)DLL,程序?qū)o法運(yùn)行。
在windows上開發(fā)多線程程序時,需要選擇MT、MTd、MD、MDd其中的一個。對于MT/MTd,由于連接運(yùn)行時庫是LIBCMT.lib/LIBCMTD.lib,這兩個庫是靜態(tài)庫,所以此種方式編譯的程序,移到另一臺機(jī)器上面也可以正常運(yùn)行,所以這種方式,不會產(chǎn)生缺少動態(tài)庫的報錯。但是對于MD/MDd,連接的是動態(tài)庫,所以如果另一臺機(jī)器上沒有MSVCRT.dll/MSVCRTD.dll時,就提示缺少動態(tài)庫這樣的錯誤。對用戶自己寫的庫或其他第三方庫,其連接方式取決于代碼(顯示連接動態(tài)庫Loadlibrary)或所提供的lib文件,移動程序到別的機(jī)器上時,還是要帶上所需要的動態(tài)庫的。在多工程開發(fā)時,最好所有的工程使用同一種運(yùn)行時庫。
運(yùn)行時安全
近年來出現(xiàn)的運(yùn)行時應(yīng)用程序自我保護(hù)技術(shù)(Runtime Application Self-Protection,簡稱RASP),是一種解決應(yīng)用程序漏洞問題并為IT基礎(chǔ)架構(gòu)增加額外安全層的方法。根據(jù)Gartner的說法,運(yùn)行時應(yīng)用程序自我保護(hù)是“建立在或鏈接到應(yīng)用程序運(yùn)行時環(huán)境的安全技術(shù),它能夠控制應(yīng)用程序的執(zhí)行,并且檢測和阻止實時攻擊?!?/p>
運(yùn)行時應(yīng)用程序自我保護(hù)是預(yù)防性的,它可以采取多種措施來阻止黑客破壞系統(tǒng),在出現(xiàn)問題時控制應(yīng)用程序。除了檢測惡意代碼,RASP還可以:
- 突然結(jié)束用戶會話
- 關(guān)閉應(yīng)用程序或系統(tǒng)
- 標(biāo)記異常事件的管理員和安全人員
- 向系統(tǒng)用戶發(fā)送警告
RASP一般與應(yīng)用程序集成,并通過監(jiān)視和分析流量以及用戶行為來防止程序運(yùn)行時受到攻擊,這使它們可以在應(yīng)用程序中看到功能級別的代碼。這種可見性使其能夠更準(zhǔn)確地識別攻擊,減少誤報并報告或阻止構(gòu)成合法威脅的那些動作。
常見的運(yùn)行時環(huán)境
這里,我們來了解不同編程語言的運(yùn)行時環(huán)境,包括C語言的操作系統(tǒng)運(yùn)行機(jī)制、Apache Portable Runtime、Common Language Runtime、Java Runtime Environment、Android Runtime、iOS Runtime、JavaScript引擎與運(yùn)行時環(huán)境以及小程序的運(yùn)行時環(huán)境。進(jìn)而,思考各個運(yùn)行時環(huán)境的特點和優(yōu)劣,以及它們在不同平臺上的表現(xiàn)。
C/C++運(yùn)行時
C 語言最主要的運(yùn)行時,實際上就是操作系統(tǒng)。C 語言和現(xiàn)代的各種操作系統(tǒng)可以說是伴生關(guān)系,就像 Java 和 JVM 是伴生關(guān)系一樣。
在程序執(zhí)行機(jī)制方面,C 語言編譯完畢的程序是完全按照操作系統(tǒng)的運(yùn)行機(jī)制來執(zhí)行的。在內(nèi)存管理方面,C 語言使用了操作系統(tǒng)提供的線程棧,操作系統(tǒng)能夠自動幫助程序管理內(nèi)存。程序也可以從堆里申請內(nèi)存,但必須自己負(fù)責(zé)釋放,沒有自動內(nèi)存管理機(jī)制。在并發(fā)機(jī)制方面,當(dāng)然也是直接用操作系統(tǒng)提供的線程機(jī)制。如果操作系統(tǒng)沒有提供協(xié)程和 Actor 機(jī)制,所以 C 語言也沒有提供這種并發(fā)機(jī)制。
APR
Apache可移植運(yùn)行時(Apache Portable Runtime,簡稱APR)是Apache HTTP服務(wù)器的支持庫,提供了一組映射到下層操作系統(tǒng)的API。如果操作系統(tǒng)不支持某個特定的功能,APR將提供一個模擬實現(xiàn)。這樣程序員使用APR編寫真正可在不同平臺上移植的程序。
APR使得平臺細(xì)節(jié)的處理進(jìn)行下移。對于應(yīng)用程序而言,它們根本就不需要考慮具體的平臺,不管是Unix、Linux還是Window,應(yīng)用程序執(zhí)行的接口基本都是統(tǒng)一一致的。因此對于APR而言,可移植性和統(tǒng)一的上層接口是其考慮的一個重點。而最初,APR是作為Apache HTTP服務(wù)器的一部分而存在的,但是Apache軟件基金會將其延伸成一個單獨的項目,其他的應(yīng)用程序可以使用APR來實現(xiàn)平臺無關(guān)性。APR的目標(biāo)則是希望安全合并所有的能夠合并的代碼而不需要犧牲性能。
CLR
通用語言執(zhí)行平臺(Common Language Runtime,簡稱CLR)是微軟為他們的.NET的虛擬機(jī)所選用的名稱。它是微軟對通用語言架構(gòu)(CLI)的實例,它定義了一個程式碼執(zhí)行的環(huán)境。CLR執(zhí)行一種稱為通用中間語言的字節(jié)碼,運(yùn)行在Windows操作系統(tǒng)上。
.NET 運(yùn)行時安裝在計算機(jī)上,供依賴該框架的應(yīng)用程序使用。該運(yùn)行時具有一個廣泛的標(biāo)準(zhǔn)類庫集,稱為運(yùn)行時框架庫或基類庫 (BCL)。此外,還有運(yùn)行時庫的擴(kuò)展,這些庫為許多常見和特定于與應(yīng)用的類型、算法和實用程序功能提供實現(xiàn)。
JRE
JRE 是 Java 程序的運(yùn)行環(huán)境,其中包含一個 JAVA 虛擬機(jī)以及一些標(biāo)準(zhǔn)的函數(shù)類庫。也就是說,JRE(Java Runtime Environment)一種能夠執(zhí)行Java字節(jié)碼的虛擬機(jī),以堆棧結(jié)構(gòu)來實現(xiàn)的。JVM有自己完善的硬體架構(gòu),如處理器、堆棧、寄存器等,還具有相應(yīng)的指令系統(tǒng)。JRE屏蔽了與具體操作系統(tǒng)平臺相關(guān)的信息,使得Java程序只需生成在Java虛擬機(jī)上運(yùn)行的字節(jié)碼,就可以在多種平臺上不加修改地運(yùn)行。
作為一種編程語言的虛擬機(jī),JVM實際上不只是專用于Java語言,只要生成的編譯文件符合JVM對載入編譯文件格式要求,任何語言都可以在JRE上運(yùn)行。
ART
Android Runtime(縮寫為ART),是一種在Android操作系統(tǒng)上的運(yùn)行環(huán)境,由Google公司研發(fā),并在2013年作為Android 4.4系統(tǒng)中的一項測試功能正式對外發(fā)布,在Android 5.0及后續(xù)Android版本中作為正式的運(yùn)行時庫取代了以往的Dalvik虛擬機(jī)。ART能夠把應(yīng)用程序的字節(jié)碼轉(zhuǎn)換為機(jī)器碼,是Android所使用的一種新的虛擬機(jī)。
圖片
與Dalvik虛擬機(jī)不同的是,ART引入了AOT這種預(yù)編譯技術(shù),在應(yīng)用程序安裝的過程中,ART就已經(jīng)將所有的字節(jié)碼重新編譯成了機(jī)器碼。應(yīng)用程序運(yùn)行過程中無需進(jìn)行實時的編譯工作,只需要進(jìn)行直接調(diào)用。因此,ART極大地提高了應(yīng)用程序的運(yùn)行效率,同時也減少了手機(jī)的電量消耗,提高了移動設(shè)備的續(xù)航能力,在垃圾回收等機(jī)制上也有了較大的提升。為了保證向下兼容,ART使用了相同的Dalvik字節(jié)碼文件(dex),即在應(yīng)用程序目錄下保留了dex文件供舊程序調(diào)用,然而.odex文件則替換成了可執(zhí)行與可鏈接格式(ELF)可執(zhí)行文件。一旦一個程序被ART的dex2oat命令編譯,那么這個程序?qū)煌ㄟ^ELF可執(zhí)行文件來運(yùn)行。因此,相對于Dalvik虛擬機(jī)模式,ART模式下Android應(yīng)用程序的安裝需要消耗更多的時間,同時也會占用更大的內(nèi)部儲存空間,用于儲存編譯后的代碼,但節(jié)省了很多Dalvik虛擬機(jī)用于實時編譯的時間。
iOS Runtime
在iOS中,通常將 Runtime 理解成實現(xiàn)Obj-C語言動態(tài)的 API。Obj-C的動態(tài)性就是運(yùn)行時機(jī)制,其中最主要的是消息機(jī)制。
在iOS Runtime的支持下,動態(tài)類型和動態(tài)綁定使得選擇那個接收者以及調(diào)用哪個方法都可以在運(yùn)行時決定;應(yīng)用可以根據(jù)需要加載可執(zhí)行代碼以及資源,而不是在啟動時就加載所有資源;iOS在編譯的時候會根據(jù)方法的名字(包括參數(shù)序列),生成一個用來區(qū)分這個方法的唯一的ID,這個ID是SEL類型的,只要方法的名字(包括參數(shù)序列)相同,那么它們的ID都是相同的。通過 dlopen 把動態(tài)庫文件載入運(yùn)行的 App 里,接下來 dlsym 會得到動態(tài)庫的符號地址,然后就可以處理類的替換工作。整個過程無需重新編譯和重載 App,使用動態(tài)庫方式極速調(diào)試的目的就達(dá)成了。
JS引擎與運(yùn)行時
JavaScript 引擎是一個解釋 JavaScript 代碼的程序,該引擎負(fù)責(zé)執(zhí)行代碼。任何 JavaScript 引擎通常都包含一個調(diào)用棧和一個堆。調(diào)用棧是代碼執(zhí)行的地方,堆是一個非結(jié)構(gòu)化的內(nèi)存池,用于存儲應(yīng)用程序所需的所有對象。當(dāng)代碼片段進(jìn)入運(yùn)行時環(huán)境時,代碼首先被讀取,隨后被解析為叫作抽象語法樹(AST)的數(shù)據(jù)結(jié)構(gòu)。生成的樹被用來來創(chuàng)建機(jī)器代碼。
JavaScript 運(yùn)行時環(huán)境包含了運(yùn)行 JavaScript 所需的所有組件,包括 JavaScript 引擎、Web API 和回調(diào)隊列。
圖片
瀏覽器運(yùn)行時和 Node.js 是JS運(yùn)行時環(huán)境的具體例子。當(dāng) JavaScript 在 Web 瀏覽器中執(zhí)行時,它是在瀏覽器的運(yùn)行時環(huán)境中運(yùn)行的。瀏覽器運(yùn)行時環(huán)境提供對 DOM 的訪問,從而實現(xiàn)了與網(wǎng)頁元素的交互,處理事件,以及對頁面結(jié)構(gòu)的操作。Node.js 提供了一個服務(wù)器端運(yùn)行時環(huán)境,它在瀏覽器外部執(zhí)行 JavaScript,所以它不能訪問 Web API。Node.js 運(yùn)行時環(huán)境將其替換為叫作 C++ 綁定和線程池的東西。每個主流的瀏覽器都有一個可以執(zhí)行 JavaScript 代碼的 JavaScript 引擎。最流行的是谷歌瀏覽器 Chrome 的 V8 引擎,同時為 Chrome 和 Node.js 提供了支持。
小程序的運(yùn)行時
小程序的運(yùn)行時環(huán)境可以看作JS運(yùn)行時環(huán)境的特例。不同運(yùn)行平臺上,小程序的運(yùn)行時環(huán)境有所不同,性能表現(xiàn)也存在差異:
- 在 iOS、iPadOS 和 Mac OS 上,小程序的 JavaScript 代碼運(yùn)行在 JavaScriptCore 中,;
- 在 Android 上,小程序的 JavaScript 代碼運(yùn)行在 V8 中;
- 在 Windows 上,小程序JavaScript 使用 Chromium 內(nèi)核;
- 在 開發(fā)工具上,小程序 JavaScript 代碼一般運(yùn)行在 NW.js 中。
其中,JavaScriptCore 無法開啟 JIT 編譯,同等條件下的運(yùn)行性能要明顯低于其他平臺。
盡管各運(yùn)行環(huán)境是十分相似的,但是還是有些許區(qū)別,那就是JavaScript 語法和 API 支持存在不一致,開發(fā)者可以通過開啟 ES6 轉(zhuǎn) ES5 的功能來規(guī)避。
運(yùn)行時的云應(yīng)用
容器運(yùn)行時負(fù)責(zé)運(yùn)行容器并設(shè)置命名空間和控制組,如Docker、containerd、rkt、Kata Container、CRI-O等;FaaS的運(yùn)行時支持多種語言,每個主要編程語言版本都有單獨的運(yùn)行時,可以使用Lambda提供的運(yùn)行時或構(gòu)建自己的運(yùn)行時,也可以自定義運(yùn)行時為Shell腳本或可在Linux可執(zhí)行的二進(jìn)制文件。
容器運(yùn)行時
容器運(yùn)行時更側(cè)重于運(yùn)行容器,為容器設(shè)置命名空間和控制組(cgroup),也被稱為底層容器運(yùn)行時。高層的容器運(yùn)行時或容器引擎專注于格式、解包、管理和鏡像共享。它們還為開發(fā)者提供 API,這種情況下的容器運(yùn)行時相當(dāng)于一個可獨立運(yùn)行的模塊,可以將它視為功能性的 Native 類庫使用。
Docker是目前最廣泛的容器引擎技術(shù)。當(dāng)然,隨著容器生態(tài)圈的日益繁榮,業(yè)界慢慢也出現(xiàn)了其他各種運(yùn)行時工具,如containerd、rkt、Kata Container、CRI-O等。這些工具提供的功能不盡相同,有些只有容器運(yùn)行的功能,有些除運(yùn)行容器外還提供了容器鏡像的管理功能。
圖片
低層運(yùn)行時主要負(fù)責(zé)與宿主機(jī)操作系統(tǒng)打交道,根據(jù)指定的容器鏡像在宿主機(jī)上運(yùn)行容器的進(jìn)程,并對容器的整個生命周期進(jìn)行管理。常見的低層運(yùn)行時系統(tǒng)的種類有:
- runc:傳統(tǒng)的運(yùn)行時環(huán)境,基于Linux Namespace和Cgroups技術(shù)實現(xiàn),代表實現(xiàn)Docker
- runv:基于虛擬機(jī)管理程序的運(yùn)行時環(huán)境,通過虛擬化 guest kernel,將容器和主機(jī)隔離開來,使得其邊界更加清晰,代表實現(xiàn)是Kata Container和Firecracker
- runsc:runc + safety ,通過攔截應(yīng)用程序的所有系統(tǒng)調(diào)用,提供安全隔離的輕量級容器運(yùn)行時沙箱,代表實現(xiàn)是谷歌的gVisor
Kubernetes利用Docker作為容器運(yùn)行時管理工具,后來又添加了對rkt的支持。但隨著容器技術(shù)的蓬勃發(fā)展,越來越多的運(yùn)行時工具出現(xiàn),提供對所有運(yùn)行時工具的支持,顯然是一項龐大的工程。如果直接將運(yùn)行時的集成內(nèi)置于Kubernetes,對Kubernetes代碼本身也是一種負(fù)擔(dān),每次更新,都需要考慮對所有容器運(yùn)行時的兼容適配。因此,Kubernetes將對容器的操作抽象為一個接口,將此接口作為kubelet與運(yùn)行時工具之間的橋梁,kubelet通過發(fā)送接口請求對容器進(jìn)行啟動和管理,各個容器工具通過實現(xiàn)這個接口即可接入Kubernetes。這個統(tǒng)一的容器操作接口,就是容器運(yùn)行時接口(Container Runtime Interface, CRI)。
FaaS的運(yùn)行時
Lambda 通過使用運(yùn)行時支持多種語言。運(yùn)行時系統(tǒng)提供特定于語言的環(huán)境,用于在 Lambda 與函數(shù)之間中繼調(diào)用事件、上下文信息和響應(yīng)。我們可以使用 Lambda 提供的運(yùn)行時,或構(gòu)建您自己的運(yùn)行時。
每個主要編程語言版本都有單獨的運(yùn)行時,并具有唯一的運(yùn)行時標(biāo)識符,例如 python3.10 或 nodejs18.x。要將某個云端的函數(shù)計算配置為使用新的主要語言版本,需要更改運(yùn)行時系統(tǒng)標(biāo)識符。對于定義為容器映像的函數(shù),可以在創(chuàng)建容器映像時選擇運(yùn)行時系統(tǒng)和 Linux 發(fā)行版。要更改運(yùn)行時,需要創(chuàng)建一個新的容器映像。
在將 .zip 文件存檔作為部署程序包的時候,需要在創(chuàng)建函數(shù)時選擇運(yùn)行時。要更改運(yùn)行時,需要更新云端函數(shù)計算的配置。云服務(wù)的底層執(zhí)行環(huán)境提供了可通過函數(shù)代碼訪問的額外的庫和環(huán)境變量。
自定義的運(yùn)行時可以是Shell腳本,也可以是可在linux可執(zhí)行的二進(jìn)制文件。
小結(jié)
本文首先澄清了運(yùn)行時的核心概念,然后介紹了不同類型的運(yùn)行時環(huán)境,包括Android的ART和Dalvik虛擬機(jī)、iOS的Runtime、JavaScript引擎和運(yùn)行時環(huán)境、小程序的運(yùn)行時環(huán)境、以及云應(yīng)用的容器運(yùn)行時和FaaS的運(yùn)行時。對于容器運(yùn)行時,了解了常見的低層運(yùn)行時種類以及Kubernetes如何通過容器運(yùn)行時接口(CRI)實現(xiàn)對所有容器運(yùn)行時的支持。對于FaaS的運(yùn)行時,介紹了Lambda如何通過使用運(yùn)行時支持多種語言,并提供特定于語言的環(huán)境,用于在Lambda與函數(shù)之間中繼調(diào)用事件、上下文信息和響應(yīng)。
文章題目:老碼農(nóng)的運(yùn)行時漫談
本文網(wǎng)址:http://www.fisionsoft.com.cn/article/dhscjod.html


咨詢
建站咨詢
